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

diff -urN linux-2.5.65-bk1/Documentation/DocBook/kernel-api.tmpl linux-2.5.65-bk2/Documentation/DocBook/kernel-api.tmpl
--- linux-2.5.65-bk1/Documentation/DocBook/kernel-api.tmpl	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/Documentation/DocBook/kernel-api.tmpl	Mon Mar 31 12:39:49 2003
@@ -89,7 +89,11 @@
      <title>Memory Management in Linux</title>
      <sect1><title>The Slab Cache</title>
 !Emm/slab.c
-      </sect1>
+     </sect1>
+     <sect1><title>User Space Memory Access</title>
+!Iinclude/asm-i386/uaccess.h
+!Iarch/i386/lib/usercopy.c
+     </sect1>
   </chapter>
 
   <chapter id="proc">
diff -urN linux-2.5.65-bk1/Documentation/networking/e100.txt linux-2.5.65-bk2/Documentation/networking/e100.txt
--- linux-2.5.65-bk1/Documentation/networking/e100.txt	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/Documentation/networking/e100.txt	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
 ==============================================================
 
-September 16, 2002
+November 19, 2002
 
 
 Contents
@@ -19,7 +19,7 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of
-Adapters, version 2.1.x.  This driver includes support for Itanium(TM)-based 
+Adapters, version 2.2.x.  This driver includes support for Itanium(TM)-based 
 systems.
 
 
@@ -94,8 +94,9 @@
 Command Line Parameters
 =======================
 
-The following optional parameters are used by entering them on the command 
-line with the modprobe or insmod command using this syntax:
+If the driver is built as a module, the  following optional parameters are 
+used by entering them on the command line with the modprobe or insmod command
+using this syntax:
 
      modprobe e100 [<option>=<VAL1>,<VAL2>,...]
 
diff -urN linux-2.5.65-bk1/Documentation/networking/e1000.txt linux-2.5.65-bk2/Documentation/networking/e1000.txt
--- linux-2.5.65-bk1/Documentation/networking/e1000.txt	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/Documentation/networking/e1000.txt	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
 ===============================================================
 
-October 12, 2002
+January 8, 2003
 
 
 Contents
@@ -20,33 +20,17 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
-of Adapters, version 4.4.x.  This driver includes support for 
+of Adapters, version 5.0.x.  This driver includes support for 
 Itanium(TM)-based systems.
 
-This release version includes the following:
-
-   - Support for the ethtool 1.6 interface. A third-party application can use
-     the ethtool interface to get and set driver parameters.
-
-   - Zero copy. This feature provides faster data throughput. Enabled by
-     default in supporting kernels. It is not supported on the Intel(R)
-     PRO/1000 Gigabit Server Adapter.
-
-Features include:
-
-   - Support for the 82545 and 82546-based adapters listed below
-
-   - Wake on LAN* support via ethtool for 82540, 82544, 82545, and 82546-
-     based adapters
-
-   - Adaptive IFS for increased performance at half duplex
 
+Native VLANs are now available with supported kernels.
 
 
 Supported Adapters
 ==================
 
-The following Intel network adapters are compatible with the drivers in this
+The following Intel network adapters are compatible with the drivers in this 
 release:
 
    Controller  Adapter Name                         Board IDs
@@ -65,6 +49,7 @@
    82544       PRO/1000 T Desktop Adapter           A62947-xxx
 
    82540       PRO/1000 MT Desktop Adapter          A78408-xxx
+   82541                                            C91016-xxx
 
    82545       PRO/1000 MT Server Adapter           A92165-xxx
 
@@ -77,33 +62,42 @@
    82546       PRO/1000 MF Dual Port Server Adapter A91620-xxx
 
 
-To verify your Intel adapter is supported, find the board ID number on the
-adapter. Look for a label that has a barcode and a number in the format of
-123456-001 (six digits hyphen three digits). Match this to the list of
-numbers above.
 
-For more information on how to identify your adapter, go to the Adapter &
+To verify your Intel adapter is supported, find the board ID number on the 
+adapter. Look for a label that has a barcode and a number in the format  
+A12345-001. Match this to the list of numbers above.
+
+For more information on how to identify your adapter, go to the Adapter & 
 Driver ID Guide at:
 
     http://support.intel.com/support/network/adapter/pro100/21397.htm
 
-For the latest Intel network drivers for Linux, go to:
+For the latest Intel network drivers for Linux, refer to the following
 
-    http://appsr.intel.com/scripts-df/support_intel.asp
+    http://downloadfinder.intel.com/scripts-df/support_intel.asp
 
 
 Command Line Parameters
 =======================
 
-If the driver is built as a module, the following optional parameters are 
-used by entering them on the command line with the modprobe or insmod command. 
+If the driver is built as a module, the  following optional parameters are 
+used by entering them on the command line with the modprobe or insmod command
+using this syntax:
+
+     modprobe e1000 [<option>=<VAL1>,<VAL2>,...]
+
+     insmod e1000 [<option>=<VAL1>,<VAL2>,...] 
+
 For example, with two PRO/1000 PCI adapters, entering:
 
-    insmod e1000 TxDescriptors=80,128
+     insmod e1000 TxDescriptors=80,128
 
-loads the e1000 driver with 80 TX resources for the first adapter and 128 TX
+loads the e1000 driver with 80 TX resources for the first adapter and 128 TX 
 resources for the second adapter.
 
+The default value for each parameter is generally the recommended setting,
+unless otherwise noted.
+
 For more information about the AutoNeg, Duplex, and Speed parameters, see the
 "Speed and Duplex Configuration" section in this document.
 
@@ -129,6 +123,20 @@
     This parameter controls the automatic generation(Tx) and response(Rx) to 
     Ethernet PAUSE frames.
 
+InterruptThrottleRate
+Valid Range: 100-100000 (0=off, 1=dynamic)
+Default Value: 1
+    This value represents the maximum number of interrupts per second the 
+    controller generates. InterruptThrottleRate is another setting used in 
+    interrupt moderation. Dynamic mode uses a heuristic algorithm to adjust 
+    InterruptThrottleRate based on the current traffic load.
+
+    NOTE: InterruptThrottleRate takes precedence over the TxAbsIntDelay and 
+          RxAbsIntDelay parameters. In other words, minimizing the receive 
+          and/or transmit absolute delays does not force the controller to 
+          generate more interrupts than what the Interrupt Throttle Rate 
+          allows.
+
 RxDescriptors
 Valid Range: 80-256 for 82542 and 82543-based adapters
              80-4096 for 82540, 82544, 82545, and 82546-based adapters
@@ -154,9 +162,9 @@
     descriptors.
 
     CAUTION: When setting RxIntDelay to a value other than 0, adapters may 
-             hang (stop transmitting) under certain network conditions. If
+             hang (stop transmitting) under certain network conditions. If 
              this occurs a NETDEV WATCHDOG message is logged in the system
-             event log. In addition, the controller is automatically reset,
+             event log. In addition, the controller is automatically reset, 
              restoring the network connection. To eliminate the potential for
              the hang ensure that RxIntDelay is set to 0.
 
@@ -176,7 +184,7 @@
     Speed forces the line speed to the specified value in megabits per second
     (Mbps). If this parameter is not specified or is set to 0 and the link 
     partner is set to auto-negotiate, the board will auto-detect the correct 
-    speed. Duplex must also be set when Speed is set to either 10 or 100.
+    speed. Duplex should also be set when Speed is set to either 10 or 100.
 
 TxDescriptors
 Valid Range: 80-256 for 82542 and 82543-based adapters
@@ -190,7 +198,7 @@
 Valid Range: 0-65535 (0=off)
 Default Value: 64
     This value delays the generation of transmit interrupts in units of 
-    1.024 microseconds.  Transmit interrupt reduction can improve CPU
+    1.024 microseconds. Transmit interrupt reduction can improve CPU
     efficiency if properly tuned for specific network traffic. If the
     system is reporting dropped transmits, this value may be set too high
     causing the driver to run out of available transmit descriptors.
@@ -205,7 +213,7 @@
     along with TxIntDelay, may improve traffic throughput in specific 
     network conditions.
 
-XsumRX (not available on the PRO/1000 Gigabit Server Adapter)
+XsumRX (not available on the 82542-based adapter)
 Valid Range: 0-1
 Default Value: 1
     A value of '1' indicates that the driver should enable IP checksum
@@ -215,10 +223,10 @@
 Speed and Duplex Configuration
 ==============================
 
-Three keywords are used to control the speed and duplex configuration. These
+Three keywords are used to control the speed and duplex configuration. These 
 keywords are Speed, Duplex, and AutoNeg.
 
-If the board uses a fiber interface, these keywords are ignored, and the
+If the board uses a fiber interface, these keywords are ignored, and the 
 fiber interface board only links at 1000 Mbps full-duplex.
 
 For copper-based boards, the keywords interact as follows:
@@ -230,23 +238,23 @@
   If Speed = 1000, limited auto-negotiation is enabled and only 1000 Mbps is
   advertised (The 1000BaseT spec requires auto-negotiation.)
 
-  If Speed = 10 or 100, then both Speed and Duplex must be set. Auto-
-  negotiation is disabled, and the AutoNeg parameter is ignored. Partner MUST
+  If Speed = 10 or 100, then both Speed and Duplex should be set. Auto-
+  negotiation is disabled, and the AutoNeg parameter is ignored. Partner SHOULD
   also be forced.
 
 The AutoNeg parameter is used when more control is required over the auto-
-negotiation process.  When this parameter is used, Speed and Duplex must not
-be specified.  This parameter is a bitmap that specifies which speed and
+negotiation process.  When this parameter is used, Speed and Duplex must not 
+be specified.  This parameter is a bitmap that specifies which speed and 
 duplex settings are advertised to the link partner.
 
 Bit            7      6      5       4       3      2      1       0
 Speed (Mbps)   N/A    N/A    1000    N/A     100    100    10      10
 Duplex                       Full            Full   Half   Full    Half
 
-Note that setting AutoNeg does not guarantee that the board will link at the
-highest specified speed or duplex mode, but the board will link at the
+Note that setting AutoNeg does not guarantee that the board will link at the 
+highest specified speed or duplex mode, but the board will link at the 
 highest possible speed/duplex of the link partner IF the link partner is also
-set to auto-negotiate. If the link partner is forced speed/duplex, the
+set to auto-negotiate. If the link partner is forced speed/duplex, the 
 adapter MUST be forced to the same speed/duplex.
 
 
@@ -256,13 +264,19 @@
   Jumbo Frames
   ------------
 
-  The driver supports Jumbo Frames for all adapters except 82542-based
-  adapters.  Jumbo Frames support is enabled by changing the MTU to a value
-  larger than the default of 1500.  Use the ifconfig command to increase the
+  The driver supports Jumbo Frames for all adapters except 82542-based 
+  adapters. Jumbo Frames support is enabled by changing the MTU to a value 
+  larger than the default of 1500. Use the ifconfig command to increase the 
   MTU size. For example:
 
         ifconfig ethx mtu 9000 up
 
+  The maximum MTU setting for Jumbo Frames is 16110. This value coincides 
+  with the maximum Jumbo Frames size of 16128.
+
+  NOTE: Jumbo Frames are supported at 1000 Mbps only. Using Jumbo Frames at 
+  10 or 100 Mbps may result in poor performance or loss of link.
+
 
 Known Issues
 ============
@@ -270,33 +284,33 @@
   Jumbo Frames System Requirement
   -------------------------------
 
-  Memory allocation failures have been observed on Linux systems with 64 MB
-  of RAM or less that are running Jumbo Frames. If you are using Jumbo
-  Frames, your system may require more than the advertised minimum
+  Memory allocation failures have been observed on Linux systems with 64 MB 
+  of RAM or less that are running Jumbo Frames. If you are using Jumbo 
+  Frames, your system may require more than the advertised minimum 
   requirement of 64 MB of system memory.
 
 
 Support
 =======
 
-For general information and support, go to the Intel support website at:
+For general information, go to the Intel support website at:
 
     http://support.intel.com
 
 If an issue is identified with the released source code on the supported
-kernel with a supported adapter, email the specific information related to
+kernel with a supported adapter, email the specific information related to 
 the issue to linux.nics@intel.com.
 
 
 License
 =======
 
-This software program is released under the terms of a license agreement
-between you ('Licensee') and Intel. Do not use or load this software or any
-associated materials (collectively, the 'Software') until you have carefully
-read the full terms and conditions of the LICENSE located in this software
-package. By loading or using the Software, you agree to the terms of this
-Agreement. If you do not agree with the terms of this Agreement, do not
+This software program is released under the terms of a license agreement 
+between you ('Licensee') and Intel. Do not use or load this software or any 
+associated materials (collectively, the 'Software') until you have carefully 
+read the full terms and conditions of the LICENSE located in this software 
+package. By loading or using the Software, you agree to the terms of this 
+Agreement. If you do not agree with the terms of this Agreement, do not 
 install or use the Software.
 
 * Other names and brands may be claimed as the property of others.
diff -urN linux-2.5.65-bk1/Documentation/sound/alsa/ALSA-Configuration.txt linux-2.5.65-bk2/Documentation/sound/alsa/ALSA-Configuration.txt
--- linux-2.5.65-bk1/Documentation/sound/alsa/ALSA-Configuration.txt	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/Documentation/sound/alsa/ALSA-Configuration.txt	Mon Mar 31 12:39:50 2003
@@ -520,13 +520,19 @@
 
     Module for Envy24 (ICE1712) based PCI soundcards.
 			* MidiMan M Audio Delta 1010
+			* MidiMan M Audio Delta 1010LT
 			* MidiMan M Audio Delta DiO 2496
 			* MidiMan M Audio Delta 66
 			* MidiMan M Audio Delta 44
+			* MidiMan M Audio Delta 410
 			* MidiMan M Audio Audiophile 2496
                         * TerraTec EWS 88MT
                         * TerraTec EWS 88D
                         * TerraTec EWX 24/96
+                        * TerraTec DMX 6Fire
+                        * Hoontech SoundTrack DSP 24
+                        * Hoontech SoundTrack DSP 24 Value
+                        * Hoontech SoundTrack DSP 24 Media 7.1
 
     omni	- Omni I/O support for MidiMan M-Audio Delta44/66
 
@@ -534,6 +540,15 @@
     is not used with all Envy24 based cards (for example in the MidiMan Delta
     serie).
 
+  Module snd-ice1724
+  ------------------
+
+    Module for Envy24HT (VT/ICE1724) based PCI soundcards.
+			* MidiMan M Audio Revolution 7.1
+			* AMP Ltd AUDIO2000
+
+    Module supports up to 8 cards and autoprobe.
+
   Module snd-intel8x0
   -------------------
 
@@ -659,7 +674,7 @@
     Module supports autoprobe and multiple chips (max 8).
     Note: on some notebooks the buffer address cannot be detected
     automatically, or causes hang-up during initialization.
-    In such a case, specify the buffer top address explicitly via
+    In such a case, specify the buffer top address explicity via
     buffer_top option.
     For example,
       Sony F250: buffer_top=0x25a800
@@ -968,6 +983,19 @@
     The power-management is supported.
 
 
+Configuring Non-ISAPNP Cards
+============================
+
+When the kernel is configured with ISA-PnP support, the modules
+supporting the isapnp cards will have module options "isapnp".
+If this option is set, *only* the ISA-PnP devices will be probed.
+For probing the non ISA-PnP cards, you have to pass "isapnp=0" option
+together with the proper i/o and irq configuration.
+
+When the kernel is configured without ISA-PnP support, isapnp option
+will be not built in.
+
+
 modprobe/kmod support
 =====================
 
diff -urN linux-2.5.65-bk1/Documentation/sound/alsa/CMIPCI.txt linux-2.5.65-bk2/Documentation/sound/alsa/CMIPCI.txt
--- linux-2.5.65-bk1/Documentation/sound/alsa/CMIPCI.txt	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/Documentation/sound/alsa/CMIPCI.txt	Mon Mar 31 12:39:50 2003
@@ -207,7 +207,7 @@
 ---------------
 
 The MPU401-UART interface is enabled as default only for the first
-(CMIPCI) card.  You need to set module option "snd_midi_port" properly
+(CMIPCI) card.  You need to set module option "midi_port" properly
 for the 2nd (CMIPCI) card.
 
 There is _no_ hardware wavetable function on this chip (except for
@@ -221,7 +221,7 @@
 --------------
 
 The FM OPL/3 is also enabled as default only for the first card.
-Set "snd_fm_port" module option for more cards.
+Set "fm_port" module option for more cards.
 
 The output quality of FM OPL/3 is, however, very weird.
 I don't know why..
diff -urN linux-2.5.65-bk1/Documentation/sound/alsa/ControlNames.txt linux-2.5.65-bk2/Documentation/sound/alsa/ControlNames.txt
--- linux-2.5.65-bk1/Documentation/sound/alsa/ControlNames.txt	Mon Mar 17 13:43:51 2003
+++ linux-2.5.65-bk2/Documentation/sound/alsa/ControlNames.txt	Mon Mar 31 12:39:50 2003
@@ -80,3 +80,5 @@
   IEC958 [...] [Playback|Capture] Con Mask	/* consumer mask */
   IEC958 [...] [Playback|Capture] Pro Mask	/* professional mask */
   IEC958 [...] [Playback|Capture] PCM Stream	/* the settings assigned to a PCM stream */
+  IEC958 Q-subcode [Playback|Capture] Default	/* Q-subcode bits */
+  IEC958 Preamble [Playback|Capture] Default	/* burst preamble words (4*16bits) */
diff -urN linux-2.5.65-bk1/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl linux-2.5.65-bk2/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
--- linux-2.5.65-bk1/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl	Mon Mar 31 12:39:50 2003
@@ -48,6 +48,8 @@
      <sect1><title>Memory Management Helpers</title>
 !Esound/core/memory.c
 !Iinclude/sound/sndmagic.h
+!Esound/core/memalloc.c
+!Esound/core/sgbuf.c
      </sect1>
   </chapter>
   <chapter><title>PCM API</title>
@@ -62,9 +64,6 @@
      <sect1><title>PCM Memory Managment</title>
 !Esound/core/pcm_memory.c
      </sect1>
-     <sect1><title>SG-Buffer Helpers</title>
-!Esound/core/pcm_sgbuf.c
-     </sect1>
   </chapter>
   <chapter><title>Control/Mixer API</title>
      <sect1><title>General Control Interface</title>
diff -urN linux-2.5.65-bk1/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl linux-2.5.65-bk2/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
--- linux-2.5.65-bk1/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	Mon Mar 31 12:39:50 2003
@@ -437,7 +437,7 @@
   // (see "Management of Cards and Components")
   static int __devinit snd_mychip_create(snd_card_t *card,
                                          struct pci_device *pci,
-                                         mychip_t *rchip)
+                                         mychip_t **rchip)
   {
           mychip_t *chip;
           int err;
@@ -1377,6 +1377,8 @@
 
   module_init(alsa_card_mychip_init)
   module_exit(alsa_card_mychip_exit)
+
+  EXPORT_NO_SYMBOLS; /* for old kernels only */
 ]]>
           </programlisting>
         </example>
@@ -1664,7 +1666,7 @@
   chip->iobase_phys = pci_resource_start(pci, 0);
   chip->iobase_virt = (unsigned long)
                       ioremap_nocache(chip->iobase_phys, 512);
-  if ((chip->res_port = request_mem_region(chip->port, 512,
+  if ((chip->res_port = request_mem_region(chip->iobase_phys, 512,
                                            "My Chip")) == NULL) {
           printk(KERN_ERR "cannot allocate the memory region\n");
           snd_mychip_free(chip);
@@ -2758,6 +2760,17 @@
         </para>
       </section>
 
+      <section id="pcm-interface-operators-ack">
+        <title>ack callback</title>
+        <para>
+          This callback is also not mandatory. This callback is called
+        when the appl_ptr is updated in read or write operations.
+        Some drivers like emu10k1-fx and cs46xx need to track the
+	current appl_ptr for the internal buffer, and this callback
+	is useful only for such a purpose.
+	</para>
+      </section>
+
       <section id="pcm-interface-operators-page-callback">
         <title>page callback</title>
 
@@ -2807,7 +2820,7 @@
         </para>
 
         <para>
-          If you acquire a spinlock in the interrupt handler, and the
+          If you aquire a spinlock in the interrupt handler, and the
         lock is used in other pcm callbacks, too, then you have to
         release the lock before calling
         <function>snd_pcm_period_elapsed()</function>, because
@@ -4467,8 +4480,7 @@
         <informalexample>
           <programlisting>
 <![CDATA[
-  snd_pcm_sgbuf_t *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t,
-                              substream->dma_private, return -EINVAL);
+  snd_pcm_sgbuf_t *sgbuf = (snd_pcm_sgbuf_t*)substream->dma_private;
 ]]>
           </programlisting>
         </informalexample>
diff -urN linux-2.5.65-bk1/Documentation/sound/alsa/serial-u16550.txt linux-2.5.65-bk2/Documentation/sound/alsa/serial-u16550.txt
--- linux-2.5.65-bk1/Documentation/sound/alsa/serial-u16550.txt	Mon Mar 17 13:44:12 2003
+++ linux-2.5.65-bk2/Documentation/sound/alsa/serial-u16550.txt	Mon Mar 31 12:39:50 2003
@@ -2,7 +2,7 @@
 			Serial UART 16450/16550 MIDI driver
 			===================================
 
-The snd_adaptor module parameter allows you to select either:
+The adaptor module parameter allows you to select either:
 
   0 - Roland Soundcanvas support (default)
   1 - Midiator MS-124T support (1)
@@ -24,37 +24,35 @@
 Usage example for simple serial converter:
 
 	/sbin/setserial /dev/ttyS0 none
-	/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
-			snd_speed=115200
+	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 speed=115200
 
 Usage example for Roland SoundCanvas with 4 MIDI ports:
 
 	/sbin/setserial /dev/ttyS0 none
-	/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 snd_outs=4
+	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 outs=4
 
-In MS-124T mode, one raw MIDI substream is supported (midiCnD0); the snd_outs
+In MS-124T mode, one raw MIDI substream is supported (midiCnD0); the outs
 module parameter is automatically set to 1. The driver sends the same data to
-all four MIDI Out connectors.  Set the A-B switch and the snd_speed module
+all four MIDI Out connectors.  Set the A-B switch and the speed module
 parameter to match (A=19200, B=9600).
 
 Usage example for MS-124T, with A-B switch in A position:
 
 	/sbin/setserial /dev/ttyS0 none
-	/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
-			snd_adaptor=1 snd_speed=19200
+	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=1 \
+			speed=19200
 
 In MS-124W S/A mode, one raw MIDI substream is supported (midiCnD0);
-the snd_outs module parameter is automatically set to 1. The driver sends
+the outs module parameter is automatically set to 1. The driver sends
 the same data to all four MIDI Out connectors at full MIDI speed.
 
 Usage example for S/A mode:
 
 	/sbin/setserial /dev/ttyS0 none
-	/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
-			snd_adaptor=2
+	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=2
 
 In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI substreams;
-the snd_outs module parameter is automatically set to 16.  The substream
+the outs module parameter is automatically set to 16.  The substream
 number gives a bitmask of which MIDI Out connectors the data should be
 sent to, with midiCnD1 sending to Out 1, midiCnD2 to Out 2, midiCnD4 to
 Out 3, and midiCnD8 to Out 4.  Thus midiCnD15 sends the data to all 4 ports.
@@ -67,8 +65,7 @@
 Usage example for M/B mode:
 
 	/sbin/setserial /dev/ttyS0 none
-	/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
-			snd_adaptor=3
+	/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=3
 
 The MS-124W hardware's M/A mode is currently not supported. This mode allows
 the MIDI Outs to act independently at double the aggregate throughput of M/B,
@@ -88,4 +85,4 @@
 serial port.  Similar to Roland Soundcanvas mode, F5 NN is used to select the
 appropriate input or output stream (depending on the data direction).
 Additionally, the CTS signal is used to regulate the data flow.  The number of
-inputs is specified by the snd_ins parameter.
+inputs is specified by the ins parameter.
diff -urN linux-2.5.65-bk1/MAINTAINERS linux-2.5.65-bk2/MAINTAINERS
--- linux-2.5.65-bk1/MAINTAINERS	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/MAINTAINERS	Mon Mar 31 12:39:50 2003
@@ -923,10 +923,11 @@
 S:	Supported
 
 INTEL PRO/1000 GIGABIT ETHERNET SUPPORT
-P:	Chris Leech
-M:	christopher.leech@intel.com
+P:	Jeb Cramer
+M:	cramerj@intel.com
 P:	Scott Feldman
 M:	scott.feldman@intel.com
+W:	http://sourceforge.net/projects/e1000/
 S:	Supported
 
 INTERMEZZO FILE SYSTEM
diff -urN linux-2.5.65-bk1/Makefile linux-2.5.65-bk2/Makefile
--- linux-2.5.65-bk1/Makefile	Mon Mar 31 12:39:48 2003
+++ linux-2.5.65-bk2/Makefile	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 65
-EXTRAVERSION = -bk1
+EXTRAVERSION = -bk2
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.65-bk1/arch/i386/kernel/cpu/cpufreq/longhaul.c linux-2.5.65-bk2/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- linux-2.5.65-bk1/arch/i386/kernel/cpu/cpufreq/longhaul.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/arch/i386/kernel/cpu/cpufreq/longhaul.c	Mon Mar 31 12:39:50 2003
@@ -525,9 +525,6 @@
 {
 	struct cpuinfo_x86 *c = cpu_data;
 
-	if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) )
-		return -ENODEV;
-
 	switch (c->x86_model) {
 	case 6:		/* VIA C3 Samuel C5A */
 		longhaul=1;
diff -urN linux-2.5.65-bk1/arch/i386/kernel/cpu/cpufreq/longrun.c linux-2.5.65-bk2/arch/i386/kernel/cpu/cpufreq/longrun.c
--- linux-2.5.65-bk1/arch/i386/kernel/cpu/cpufreq/longrun.c	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/arch/i386/kernel/cpu/cpufreq/longrun.c	Mon Mar 31 12:39:50 2003
@@ -229,9 +229,6 @@
 	/* capability check */
 	if (policy->cpu != 0)
 		return -ENODEV;
-	if (c->x86_vendor != X86_VENDOR_TRANSMETA || 
-	    !cpu_has(c, X86_FEATURE_LONGRUN))
-		return -ENODEV;
 
 	/* detect low and high frequency */
 	result = longrun_determine_freqs(&longrun_low_freq, &longrun_high_freq);
diff -urN linux-2.5.65-bk1/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c linux-2.5.65-bk2/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
--- linux-2.5.65-bk1/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Mon Mar 31 12:39:50 2003
@@ -180,13 +180,6 @@
 	int cpuid = 0;
 	unsigned int i;
 
-	/* capability check */
-	if (c->x86_vendor != X86_VENDOR_INTEL)
-		return -ENODEV;
-	if (!test_bit(X86_FEATURE_ACPI, c->x86_capability) ||
-	    !test_bit(X86_FEATURE_ACC, c->x86_capability))
-		return -ENODEV;
-	
 	/* Errata workaround */
 	cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask;
 	switch (cpuid) {
diff -urN linux-2.5.65-bk1/arch/i386/kernel/cpu/cpufreq/powernow-k6.c linux-2.5.65-bk2/arch/i386/kernel/cpu/cpufreq/powernow-k6.c
--- linux-2.5.65-bk1/arch/i386/kernel/cpu/cpufreq/powernow-k6.c	Mon Mar 17 13:43:42 2003
+++ linux-2.5.65-bk2/arch/i386/kernel/cpu/cpufreq/powernow-k6.c	Mon Mar 31 12:39:50 2003
@@ -145,10 +145,6 @@
 	struct cpuinfo_x86 *c = cpu_data;
 	unsigned int i;
 
-	/* capability check */
-	if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
-	    ((c->x86_model != 12) && (c->x86_model != 13)))
-		return -ENODEV;
 	if (policy->cpu != 0)
 		return -ENODEV;
 
diff -urN linux-2.5.65-bk1/arch/i386/kernel/entry.S linux-2.5.65-bk2/arch/i386/kernel/entry.S
--- linux-2.5.65-bk1/arch/i386/kernel/entry.S	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/arch/i386/kernel/entry.S	Mon Mar 31 12:39:50 2003
@@ -73,10 +73,10 @@
 VM_MASK		= 0x00020000
 
 /*
- * ESP0 is at offset 4. 0x100 is the size of the TSS, and
+ * ESP0 is at offset 4. 0x200 is the size of the TSS, and
  * also thus the top-of-stack pointer offset of SYSENTER_ESP
  */
-TSS_ESP0_OFFSET = (4 - 0x100)
+TSS_ESP0_OFFSET = (4 - 0x200)
 
 #ifdef CONFIG_PREEMPT
 #define preempt_stop		cli
@@ -479,23 +479,32 @@
  * by hand onto the new stack - while updating the return eip past
  * the instruction that would have done it for sysenter.
  */
-#define CHECK_SYSENTER_EIP			\
-	cmpl $sysenter_entry,(%esp);		\
-	jne 1f;					\
-	movl TSS_ESP0_OFFSET+12(%esp),%esp;	\
+#define FIX_STACK(offset, ok, label)		\
+	cmpw $__KERNEL_CS,4(%esp);		\
+	jne ok;					\
+label:						\
+	movl TSS_ESP0_OFFSET+offset(%esp),%esp;	\
 	pushfl;					\
 	pushl $__KERNEL_CS;			\
-	pushl $sysenter_past_esp;		\
-1:
+	pushl $sysenter_past_esp
 
 ENTRY(debug)
-	CHECK_SYSENTER_EIP
+	cmpl $sysenter_entry,(%esp)
+	jne debug_stack_correct
+	FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
+debug_stack_correct:
 	pushl $0
 	pushl $do_debug
 	jmp error_code
 
 ENTRY(nmi)
-	CHECK_SYSENTER_EIP
+	cmpl $sysenter_entry,(%esp)
+	je nmi_stack_fixup
+	cmpl $debug - 1,(%esp)
+	jle nmi_stack_correct
+	cmpl $debug_esp_fix_insn,(%esp)
+	jle nmi_debug_stack_fixup
+nmi_stack_correct:
 	pushl %eax
 	SAVE_ALL
 	movl %esp, %edx
@@ -505,6 +514,13 @@
 	addl $8, %esp
 	RESTORE_ALL
 
+nmi_stack_fixup:
+	FIX_STACK(12,nmi_stack_correct, 1)
+	jmp nmi_stack_correct
+nmi_debug_stack_fixup:
+	FIX_STACK(24,nmi_stack_correct, 1)
+	jmp nmi_stack_correct
+
 ENTRY(int3)
 	pushl $0
 	pushl $do_int3
diff -urN linux-2.5.65-bk1/arch/i386/kernel/io_apic.c linux-2.5.65-bk2/arch/i386/kernel/io_apic.c
--- linux-2.5.65-bk1/arch/i386/kernel/io_apic.c	Mon Mar 31 12:39:48 2003
+++ linux-2.5.65-bk2/arch/i386/kernel/io_apic.c	Mon Mar 31 12:39:50 2003
@@ -2081,7 +2081,7 @@
 	}
 	printk(" failed.\n");
 
-	if (nmi_watchdog) {
+	if (nmi_watchdog == NMI_IO_APIC) {
 		printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
 		nmi_watchdog = 0;
 	}
diff -urN linux-2.5.65-bk1/arch/i386/kernel/irq.c linux-2.5.65-bk2/arch/i386/kernel/irq.c
--- linux-2.5.65-bk1/arch/i386/kernel/irq.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/arch/i386/kernel/irq.c	Mon Mar 31 12:39:50 2003
@@ -744,6 +744,8 @@
 	struct irqaction *old, **p;
 	irq_desc_t *desc = irq_desc + irq;
 
+	if (desc->handler == &no_irq_type)
+		return -ENOSYS;
 	/*
 	 * Some drivers like serial.c use request_irq() heavily,
 	 * so we have to be careful not to interfere with a
diff -urN linux-2.5.65-bk1/arch/i386/kernel/timers/timer_tsc.c linux-2.5.65-bk2/arch/i386/kernel/timers/timer_tsc.c
--- linux-2.5.65-bk1/arch/i386/kernel/timers/timer_tsc.c	Mon Mar 17 13:44:19 2003
+++ linux-2.5.65-bk2/arch/i386/kernel/timers/timer_tsc.c	Mon Mar 31 12:39:50 2003
@@ -213,6 +213,7 @@
 {
 	struct cpufreq_freqs *freq = data;
 
+	write_seqlock(&xtime_lock);
 	if (!ref_freq) {
 		ref_freq = freq->old;
 		loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
@@ -232,6 +233,7 @@
 		}
 #endif
 	}
+	write_sequnlock(&xtime_lock);
 
 	return 0;
 }
diff -urN linux-2.5.65-bk1/arch/i386/lib/usercopy.c linux-2.5.65-bk2/arch/i386/lib/usercopy.c
--- linux-2.5.65-bk1/arch/i386/lib/usercopy.c	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/arch/i386/lib/usercopy.c	Mon Mar 31 12:39:50 2003
@@ -50,6 +50,26 @@
 		: "memory");						   \
 } while (0)
 
+/**
+ * __strncpy_from_user: - Copy a NULL terminated string from userspace, with less checking.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NULL.
+ * 
+ * Copies a NULL-terminated string from userspace to kernel space.
+ * Caller must check the specified block with access_ok() before calling
+ * this function.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NULL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
 long
 __strncpy_from_user(char *dst, const char *src, long count)
 {
@@ -58,6 +78,24 @@
 	return res;
 }
 
+/**
+ * strncpy_from_user: - Copy a NULL terminated string from userspace.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NULL.
+ * 
+ * Copies a NULL-terminated string from userspace to kernel space.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NULL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
 long
 strncpy_from_user(char *dst, const char *src, long count)
 {
@@ -93,6 +131,16 @@
 		: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0));	\
 } while (0)
 
+/**
+ * clear_user: - Zero a block of memory in user space.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
 unsigned long
 clear_user(void *to, unsigned long n)
 {
@@ -101,6 +149,17 @@
 	return n;
 }
 
+/**
+ * __clear_user: - Zero a block of memory in user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
 unsigned long
 __clear_user(void *to, unsigned long n)
 {
@@ -108,12 +167,17 @@
 	return n;
 }
 
-/*
- * Return the size of a string (including the ending 0)
+/**
+ * strlen_user: - Get the size of a string in user space.
+ * @s: The string to measure.
+ * @n: The maximum valid length
  *
- * Return 0 on exception, a value greater than N if too long
+ * Get the size of a NULL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NULL.
+ * On exception, returns 0.
+ * If the string is too long, returns a value greater than @n.
  */
-
 long strnlen_user(const char *s, long n)
 {
 	unsigned long mask = -__addr_ok(s);
diff -urN linux-2.5.65-bk1/arch/m68k/Kconfig linux-2.5.65-bk2/arch/m68k/Kconfig
--- linux-2.5.65-bk1/arch/m68k/Kconfig	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/arch/m68k/Kconfig	Mon Mar 31 12:39:50 2003
@@ -499,8 +499,8 @@
 	  uses.
 
 config HEARTBEAT
-	bool "Use power LED as a heartbeat" if AMIGA || ATARI || Q40
-	default y if !AMIGA && !ATARI && !Q40 && HP300
+	bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
+	default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
 	help
 	  Use the power-on LED on your machine as a load meter.  The exact
 	  behavior is platform-dependent, but normally the flash frequency is
diff -urN linux-2.5.65-bk1/arch/m68k/amiga/amisound.c linux-2.5.65-bk2/arch/m68k/amiga/amisound.c
--- linux-2.5.65-bk1/arch/m68k/amiga/amisound.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/arch/m68k/amiga/amisound.c	Mon Mar 31 12:39:50 2003
@@ -12,6 +12,7 @@
 #include <linux/jiffies.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/string.h>
 
 #include <asm/system.h>
 #include <asm/amigahw.h>
diff -urN linux-2.5.65-bk1/arch/m68k/amiga/chipram.c linux-2.5.65-bk2/arch/m68k/amiga/chipram.c
--- linux-2.5.65-bk1/arch/m68k/amiga/chipram.c	Mon Mar 17 13:44:11 2003
+++ linux-2.5.65-bk2/arch/m68k/amiga/chipram.c	Mon Mar 31 12:39:50 2003
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <asm/page.h>
 #include <asm/amigahw.h>
 
diff -urN linux-2.5.65-bk1/arch/m68k/amiga/config.c linux-2.5.65-bk2/arch/m68k/amiga/config.c
--- linux-2.5.65-bk1/arch/m68k/amiga/config.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/arch/m68k/amiga/config.c	Mon Mar 31 12:39:50 2003
@@ -21,6 +21,7 @@
 #include <linux/rtc.h>
 #include <linux/init.h>
 #include <linux/vt_kern.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #ifdef CONFIG_ZORRO
 #include <linux/zorro.h>
@@ -89,6 +90,7 @@
 static int a3000_hwclk (int, struct rtc_time *);
 static int a2000_hwclk (int, struct rtc_time *);
 static int amiga_set_clock_mmss (unsigned long);
+static unsigned int amiga_get_ss (void);
 extern void amiga_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_AMIGA_FLOPPY
 extern void amiga_floppy_setup(char *, int *);
@@ -403,6 +405,7 @@
 				      */
 
   mach_set_clock_mmss  = amiga_set_clock_mmss;
+  mach_get_ss          = amiga_get_ss; 
 #ifdef CONFIG_AMIGA_FLOPPY
   mach_floppy_setup    = amiga_floppy_setup;
 #endif
@@ -545,96 +548,101 @@
 
 static int a3000_hwclk(int op, struct rtc_time *t)
 {
-	volatile struct tod3000 *tod = TOD_3000;
-
-	tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+	tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
 
 	if (!op) { /* read */
-		t->tm_sec  = tod->second1 * 10 + tod->second2;
-		t->tm_min  = tod->minute1 * 10 + tod->minute2;
-		t->tm_hour = tod->hour1   * 10 + tod->hour2;
-		t->tm_mday = tod->day1    * 10 + tod->day2;
-		t->tm_wday = tod->weekday;
-		t->tm_mon  = tod->month1  * 10 + tod->month2 - 1;
-		t->tm_year = tod->year1   * 10 + tod->year2;
+		t->tm_sec  = tod_3000.second1 * 10 + tod_3000.second2;
+		t->tm_min  = tod_3000.minute1 * 10 + tod_3000.minute2;
+		t->tm_hour = tod_3000.hour1   * 10 + tod_3000.hour2;
+		t->tm_mday = tod_3000.day1    * 10 + tod_3000.day2;
+		t->tm_wday = tod_3000.weekday;
+		t->tm_mon  = tod_3000.month1  * 10 + tod_3000.month2 - 1;
+		t->tm_year = tod_3000.year1   * 10 + tod_3000.year2;
 		if (t->tm_year <= 69)
 			t->tm_year += 100;
 	} else {
-		tod->second1 = t->tm_sec / 10;
-		tod->second2 = t->tm_sec % 10;
-		tod->minute1 = t->tm_min / 10;
-		tod->minute2 = t->tm_min % 10;
-		tod->hour1   = t->tm_hour / 10;
-		tod->hour2   = t->tm_hour % 10;
-		tod->day1    = t->tm_mday / 10;
-		tod->day2    = t->tm_mday % 10;
+		tod_3000.second1 = t->tm_sec / 10;
+		tod_3000.second2 = t->tm_sec % 10;
+		tod_3000.minute1 = t->tm_min / 10;
+		tod_3000.minute2 = t->tm_min % 10;
+		tod_3000.hour1   = t->tm_hour / 10;
+		tod_3000.hour2   = t->tm_hour % 10;
+		tod_3000.day1    = t->tm_mday / 10;
+		tod_3000.day2    = t->tm_mday % 10;
 		if (t->tm_wday != -1)
-			tod->weekday = t->tm_wday;
-		tod->month1  = (t->tm_mon + 1) / 10;
-		tod->month2  = (t->tm_mon + 1) % 10;
+			tod_3000.weekday = t->tm_wday;
+		tod_3000.month1  = (t->tm_mon + 1) / 10;
+		tod_3000.month2  = (t->tm_mon + 1) % 10;
 		if (t->tm_year >= 100)
 			t->tm_year -= 100;
-		tod->year1   = t->tm_year / 10;
-		tod->year2   = t->tm_year % 10;
+		tod_3000.year1   = t->tm_year / 10;
+		tod_3000.year2   = t->tm_year % 10;
 	}
 
-	tod->cntrl1 = TOD3000_CNTRL1_FREE;
+	tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
 
 	return 0;
 }
 
 static int a2000_hwclk(int op, struct rtc_time *t)
 {
-	volatile struct tod2000 *tod = TOD_2000;
+	int cnt = 5;
+
+	tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD;
 
-	tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+	while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+	{
+	        tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+	        udelay(70);
+	        tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+	}
 
-	while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-		;
+	if (!cnt)
+		printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
 
 	if (!op) { /* read */
-		t->tm_sec  = tod->second1     * 10 + tod->second2;
-		t->tm_min  = tod->minute1     * 10 + tod->minute2;
-		t->tm_hour = (tod->hour1 & 3) * 10 + tod->hour2;
-		t->tm_mday = tod->day1        * 10 + tod->day2;
-		t->tm_wday = tod->weekday;
-		t->tm_mon  = tod->month1      * 10 + tod->month2 - 1;
-		t->tm_year = tod->year1       * 10 + tod->year2;
+		t->tm_sec  = tod_2000.second1     * 10 + tod_2000.second2;
+		t->tm_min  = tod_2000.minute1     * 10 + tod_2000.minute2;
+		t->tm_hour = (tod_2000.hour1 & 3) * 10 + tod_2000.hour2;
+		t->tm_mday = tod_2000.day1        * 10 + tod_2000.day2;
+		t->tm_wday = tod_2000.weekday;
+		t->tm_mon  = tod_2000.month1      * 10 + tod_2000.month2 - 1;
+		t->tm_year = tod_2000.year1       * 10 + tod_2000.year2;
 		if (t->tm_year <= 69)
 			t->tm_year += 100;
 
-		if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
-			if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
+		if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){
+			if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
 				t->tm_hour = 0;
-			else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
+			else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
 				t->tm_hour += 12;
 		}
 	} else {
-		tod->second1 = t->tm_sec / 10;
-		tod->second2 = t->tm_sec % 10;
-		tod->minute1 = t->tm_min / 10;
-		tod->minute2 = t->tm_min % 10;
-		if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE)
-			tod->hour1 = t->tm_hour / 10;
+		tod_2000.second1 = t->tm_sec / 10;
+		tod_2000.second2 = t->tm_sec % 10;
+		tod_2000.minute1 = t->tm_min / 10;
+		tod_2000.minute2 = t->tm_min % 10;
+		if (tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)
+			tod_2000.hour1 = t->tm_hour / 10;
 		else if (t->tm_hour >= 12)
-			tod->hour1 = TOD2000_HOUR1_PM +
+			tod_2000.hour1 = TOD2000_HOUR1_PM +
 				(t->tm_hour - 12) / 10;
 		else
-			tod->hour1 = t->tm_hour / 10;
-		tod->hour2   = t->tm_hour % 10;
-		tod->day1    = t->tm_mday / 10;
-		tod->day2    = t->tm_mday % 10;
+			tod_2000.hour1 = t->tm_hour / 10;
+		tod_2000.hour2   = t->tm_hour % 10;
+		tod_2000.day1    = t->tm_mday / 10;
+		tod_2000.day2    = t->tm_mday % 10;
 		if (t->tm_wday != -1)
-			tod->weekday = t->tm_wday;
-		tod->month1  = (t->tm_mon + 1) / 10;
-		tod->month2  = (t->tm_mon + 1) % 10;
+			tod_2000.weekday = t->tm_wday;
+		tod_2000.month1  = (t->tm_mon + 1) / 10;
+		tod_2000.month2  = (t->tm_mon + 1) % 10;
 		if (t->tm_year >= 100)
 			t->tm_year -= 100;
-		tod->year1   = t->tm_year / 10;
-		tod->year2   = t->tm_year % 10;
+		tod_2000.year1   = t->tm_year / 10;
+		tod_2000.year2   = t->tm_year % 10;
 	}
 
-	tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+	tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 
 	return 0;
 }
@@ -644,35 +652,54 @@
 	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
 
 	if (AMIGAHW_PRESENT(A3000_CLK)) {
-		volatile struct tod3000 *tod = TOD_3000;
-
-		tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
 
-		tod->second1 = real_seconds / 10;
-		tod->second2 = real_seconds % 10;
-		tod->minute1 = real_minutes / 10;
-		tod->minute2 = real_minutes % 10;
+		tod_3000.second1 = real_seconds / 10;
+		tod_3000.second2 = real_seconds % 10;
+		tod_3000.minute1 = real_minutes / 10;
+		tod_3000.minute2 = real_minutes % 10;
 		
-		tod->cntrl1 = TOD3000_CNTRL1_FREE;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
 	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-		volatile struct tod2000 *tod = TOD_2000;
+		int cnt = 5;
+
+		tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		
+		while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+		{
+			tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+			udelay(70);
+			tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		}
 
-		tod->cntrl1 = TOD2000_CNTRL1_HOLD;
-	    
-		while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-			;
-
-		tod->second1 = real_seconds / 10;
-		tod->second2 = real_seconds % 10;
-		tod->minute1 = real_minutes / 10;
-		tod->minute2 = real_minutes % 10;
+		if (!cnt)
+			printk(KERN_INFO "set_clock_mmss: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
 
-		tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+		tod_2000.second1 = real_seconds / 10;
+		tod_2000.second2 = real_seconds % 10;
+		tod_2000.minute1 = real_minutes / 10;
+		tod_2000.minute2 = real_minutes % 10;
+
+		tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 	}
 
 	return 0;
 }
 
+static unsigned int amiga_get_ss( void )
+{
+	unsigned int s;
+
+	if (AMIGAHW_PRESENT(A3000_CLK)) {
+		tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
+		s = tod_3000.second1 * 10 + tod_3000.second2;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
+	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { 
+		s = tod_2000.second1 * 10 + tod_2000.second2;
+	}
+	return s;
+}
+
 static NORET_TYPE void amiga_reset( void )
     ATTRIB_NORET;
 
diff -urN linux-2.5.65-bk1/arch/m68k/apollo/config.c linux-2.5.65-bk2/arch/m68k/apollo/config.c
--- linux-2.5.65-bk1/arch/m68k/apollo/config.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/arch/m68k/apollo/config.c	Mon Mar 31 12:39:50 2003
@@ -48,7 +48,6 @@
 static void dn_timer_int(int irq,void *, struct pt_regs *);
 static void (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL;
 static void dn_get_model(char *model);
-static int dn_cpuctrl=0xff00;
 static const char *apollo_models[] = {
 	"DN3000 (Otter)",
 	"DN3010 (Otter)",
@@ -290,6 +289,8 @@
 }
 
 #ifdef CONFIG_HEARTBEAT
+static int dn_cpuctrl=0xff00;
+
 static void dn_heartbeat(int on) {
 
 	if(on) { 
diff -urN linux-2.5.65-bk1/arch/m68k/apollo/dma.c linux-2.5.65-bk2/arch/m68k/apollo/dma.c
--- linux-2.5.65-bk1/arch/m68k/apollo/dma.c	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/arch/m68k/apollo/dma.c	Mon Mar 31 12:39:50 2003
@@ -10,6 +10,7 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/apollodma.h>
+#include <asm/io.h>
 
 /* note only works for 16 Bit 1 page DMA's */
 
@@ -27,7 +28,7 @@
 #if 0
 		printk("phys_addr: %x, page_aligned_addr: %x, start_map_addr: %x\n",phys_addr,page_aligned_addr,start_map_addr+i);
 #endif
-		outw(start_map_addr+i, xlat_map_entry);
+		out_be16(xlat_map_entry, start_map_addr+i);
 	}
 
 	next_free_xlat_entry+=2;
diff -urN linux-2.5.65-bk1/arch/m68k/atari/ataints.c linux-2.5.65-bk2/arch/m68k/atari/ataints.c
--- linux-2.5.65-bk1/arch/m68k/atari/ataints.c	Mon Mar 17 13:43:44 2003
+++ linux-2.5.65-bk2/arch/m68k/atari/ataints.c	Mon Mar 31 12:39:50 2003
@@ -273,29 +273,29 @@
 /* Dummy function to allow asm with operands.  */
 void atari_fast_prio_irq_dummy (void) {
 __asm__ (__ALIGN_STR "\n"
-"atari_fast_irq_handler:
-	orw 	#0x700,%%sr		/* disable all interrupts */
-atari_prio_irq_handler:\t
-	addl	%3,%2\n"		/* preempt_count() += HARDIRQ_OFFSET */
-	SAVE_ALL_INT "\n"
-	GET_CURRENT(%%d0) "
+"atari_fast_irq_handler:\n\t"
+	"orw 	#0x700,%%sr\n"		/* disable all interrupts */
+"atari_prio_irq_handler:\n\t"
+	"addl	%3,%2\n\t"		/* preempt_count() += HARDIRQ_OFFSET */
+	SAVE_ALL_INT "\n\t"
+	GET_CURRENT(%%d0) "\n\t"
 	/* get vector number from stack frame and convert to source */
-	bfextu	%%sp@(%c1){#4,#10},%%d0
-	subw	#(0x40-8),%%d0
-	jpl 	1f
-	addw	#(0x40-8-0x18),%%d0
-1:	lea	%a0,%%a0
-	addql	#1,%%a0@(%%d0:l:4)
-	lea	irq_handler,%%a0
-	lea	%%a0@(%%d0:l:8),%%a0
-	pea 	%%sp@			/* push frame address */
-	movel	%%a0@(4),%%sp@-		/* push handler data */
-	movel	%%d0,%%sp@-		/* push int number */
-	movel	%%a0@,%%a0
-	jsr	%%a0@			/* and call the handler */
-	addql	#8,%%sp
-	addql	#4,%%sp
-	jbra	ret_from_interrupt"
+	"bfextu	%%sp@(%c1){#4,#10},%%d0\n\t"
+	"subw	#(0x40-8),%%d0\n\t"
+	"jpl 	1f\n\t"
+	"addw	#(0x40-8-0x18),%%d0\n"
+    "1:\tlea	%a0,%%a0\n\t"
+	"addql	#1,%%a0@(%%d0:l:4)\n\t"
+	"lea	irq_handler,%%a0\n\t"
+	"lea	%%a0@(%%d0:l:8),%%a0\n\t"
+	"pea 	%%sp@\n\t"		/* push frame address */
+	"movel	%%a0@(4),%%sp@-\n\t"	/* push handler data */
+	"movel	%%d0,%%sp@-\n\t"	/* push int number */
+	"movel	%%a0@,%%a0\n\t"
+	"jsr	%%a0@\n\t"		/* and call the handler */
+	"addql	#8,%%sp\n\t"
+	"addql	#4,%%sp\n\t"
+	"jbra	ret_from_interrupt"
 	 : : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC),
 	     "m" (preempt_count()), "di" (HARDIRQ_OFFSET)
 );
@@ -308,10 +308,10 @@
  */
 asmlinkage void falcon_hblhandler(void);
 asm(".text\n"
-__ALIGN_STR "\n"
-"falcon_hblhandler:
-	orw	#0x200,%sp@	/* set saved ipl to 2 */
-	rte");
+__ALIGN_STR "\n\t"
+"falcon_hblhandler:\n\t"
+	"orw	#0x200,%sp@\n\t"	/* set saved ipl to 2 */
+	"rte");
 
 /* Defined in entry.S; only increments 'num_spurious' */
 asmlinkage void bad_interrupt(void);
diff -urN linux-2.5.65-bk1/arch/m68k/atari/stram.c linux-2.5.65-bk2/arch/m68k/atari/stram.c
--- linux-2.5.65-bk1/arch/m68k/atari/stram.c	Mon Mar 17 13:44:22 2003
+++ linux-2.5.65-bk2/arch/m68k/atari/stram.c	Mon Mar 31 12:39:50 2003
@@ -146,7 +146,7 @@
 
 /* The following two numbers define the maximum fraction of ST-RAM in total
  * memory, below that the kernel would automatically use ST-RAM as swap
- * space. This decision can be overriden with stram_swap= */
+ * space. This decision can be overridden with stram_swap= */
 #define MAX_STRAM_FRACTION_NOM		1
 #define MAX_STRAM_FRACTION_DENOM	3
 
@@ -347,7 +347,7 @@
 		/*
 		 * If the whole ST-RAM is used for swapping, there are no allocatable
 		 * dma pages left. But unfortunately, some shared parts of the kernel
-		 * (particularily the SCSI mid-level) call __get_dma_pages()
+		 * (particularly the SCSI mid-level) call __get_dma_pages()
 		 * unconditionally :-( These calls then fail, and scsi.c even doesn't
 		 * check for NULL return values and just crashes. The quick fix for
 		 * this (instead of doing much clean up work in the SCSI code) is to
diff -urN linux-2.5.65-bk1/arch/m68k/ifpsp060/fskeleton.S linux-2.5.65-bk2/arch/m68k/ifpsp060/fskeleton.S
--- linux-2.5.65-bk1/arch/m68k/ifpsp060/fskeleton.S	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/arch/m68k/ifpsp060/fskeleton.S	Mon Mar 31 12:39:50 2003
@@ -302,7 +302,6 @@
 
 | The size of this section MUST be 128 bytes!!!
 
-	.global	_FP_CALL_TOP
 _FP_CALL_TOP:
 	.long	_060_real_bsun		- _FP_CALL_TOP
 	.long	_060_real_snan		- _FP_CALL_TOP
diff -urN linux-2.5.65-bk1/arch/m68k/ifpsp060/iskeleton.S linux-2.5.65-bk2/arch/m68k/ifpsp060/iskeleton.S
--- linux-2.5.65-bk1/arch/m68k/ifpsp060/iskeleton.S	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/arch/m68k/ifpsp060/iskeleton.S	Mon Mar 31 12:39:50 2003
@@ -270,7 +270,6 @@
 
 | The size of this section MUST be 128 bytes!!!
 
-	.global	_I_CALL_TOP
 _I_CALL_TOP:
 	.long	_060_real_chk		- _I_CALL_TOP
 	.long	_060_real_divbyzero	- _I_CALL_TOP
diff -urN linux-2.5.65-bk1/arch/m68k/kernel/entry.S linux-2.5.65-bk2/arch/m68k/kernel/entry.S
--- linux-2.5.65-bk1/arch/m68k/kernel/entry.S	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/arch/m68k/kernel/entry.S	Mon Mar 31 12:39:50 2003
@@ -33,7 +33,6 @@
  *		 for 68040
  */
 
-#include <linux/sys.h>
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/entry.h>
@@ -41,6 +40,7 @@
 #include <asm/setup.h>
 #include <asm/segment.h>
 #include <asm/traps.h>
+#include <asm/unistd.h>
 
 #include "m68k_defs.h"
 
@@ -661,7 +661,3 @@
 	.long sys_lremovexattr
 	.long sys_fremovexattr
 	.long sys_futex		/* 235 */
-
-	.rept NR_syscalls-(.-sys_call_table)/4
-		.long sys_ni_syscall
-	.endr
diff -urN linux-2.5.65-bk1/arch/m68k/kernel/head.S linux-2.5.65-bk2/arch/m68k/kernel/head.S
--- linux-2.5.65-bk1/arch/m68k/kernel/head.S	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/arch/m68k/kernel/head.S	Mon Mar 31 12:39:50 2003
@@ -190,7 +190,7 @@
  *
  * options
  * -------
- *	There are many options availble in a build of this file.  I've
+ *	There are many options available in a build of this file.  I've
  * taken the time to describe them here to save you the time of searching
  * for them and trying to understand what they mean.
  *
diff -urN linux-2.5.65-bk1/arch/m68k/kernel/m68k_ksyms.c linux-2.5.65-bk2/arch/m68k/kernel/m68k_ksyms.c
--- linux-2.5.65-bk1/arch/m68k/kernel/m68k_ksyms.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/arch/m68k/kernel/m68k_ksyms.c	Mon Mar 31 12:39:50 2003
@@ -53,11 +53,15 @@
 EXPORT_SYMBOL(mach_get_ss);
 EXPORT_SYMBOL(mach_get_rtc_pll);
 EXPORT_SYMBOL(mach_set_rtc_pll);
+#ifdef CONFIG_INPUT_M68K_BEEP_MODULE
+EXPORT_SYMBOL(mach_beep);
+#endif
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_thread);
diff -urN linux-2.5.65-bk1/arch/m68k/kernel/process.c linux-2.5.65-bk2/arch/m68k/kernel/process.c
--- linux-2.5.65-bk1/arch/m68k/kernel/process.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/arch/m68k/kernel/process.c	Mon Mar 31 12:39:50 2003
@@ -42,6 +42,7 @@
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 union thread_union init_thread_union
diff -urN linux-2.5.65-bk1/arch/m68k/kernel/signal.c linux-2.5.65-bk2/arch/m68k/kernel/signal.c
--- linux-2.5.65-bk1/arch/m68k/kernel/signal.c	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/arch/m68k/kernel/signal.c	Mon Mar 31 12:39:50 2003
@@ -16,7 +16,7 @@
  * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
  *
  * mathemu support by Roman Zippel
- *  (Note: fpstate in the signal context is completly ignored for the emulator
+ *  (Note: fpstate in the signal context is completely ignored for the emulator
  *         and the internal floating point format is put on stack)
  */
 
@@ -1019,7 +1019,7 @@
 				/* Restart the system call the same way as
 				   if the process were not traced.  */
 				struct k_sigaction *ka =
-					&current->sig->action[signr-1];
+					&current->sighand->action[signr-1];
 				int has_handler =
 					(ka->sa.sa_handler != SIG_IGN &&
 					 ka->sa.sa_handler != SIG_DFL);
@@ -1060,7 +1060,7 @@
 			}
 		}
 
-		ka = &current->sig->action[signr-1];
+		ka = &current->sighand->action[signr-1];
 		if (ka->sa.sa_handler == SIG_IGN) {
 			if (signr != SIGCHLD)
 				continue;
@@ -1087,11 +1087,11 @@
 				/* FALLTHRU */
 
 			case SIGSTOP: {
-				struct signal_struct *sig;
+				struct sighand_struct *sighand;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				sig = current->parent->sig;
-				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags 
+				sighand = current->parent->sighand;
+				if (sighand && !(sighand->action[SIGCHLD-1].sa.sa_flags 
 					     & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
@@ -1106,7 +1106,7 @@
 				/* FALLTHRU */
 
 			default:
-				sig_exit(signr, exit_code, &info);
+				do_group_exit(signr);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.5.65-bk1/arch/m68k/kernel/time.c linux-2.5.65-bk2/arch/m68k/kernel/time.c
--- linux-2.5.65-bk1/arch/m68k/kernel/time.c	Mon Mar 17 13:43:49 2003
+++ linux-2.5.65-bk2/arch/m68k/kernel/time.c	Mon Mar 31 12:39:50 2003
@@ -59,35 +59,11 @@
  */
 static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
 {
-	/* last time the cmos clock got updated */
-	static long last_rtc_update=0;
-
 	do_timer(regs);
 
 	if (!user_mode(regs))
 		do_profile(regs->pc);
 
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 */
-	/*
-	 * This code hopefully becomes obsolete in 2.5 or earlier
-	 * Should it ever be reenabled it must be serialized with
-	 * genrtc.c operation
-	 */
-#if 0
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) tick) / 2 &&
-	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) tick) / 2) {
-	  if (set_rtc_mmss(xtime.tv_sec) == 0)
-	    last_rtc_update = xtime.tv_sec;
-	  else
-	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-	}
-#endif
 #ifdef CONFIG_HEARTBEAT
 	/* use power LED as a heartbeat instead -- much more useful
 	   for debugging -- based on the version for PReP by Cort */
diff -urN linux-2.5.65-bk1/arch/m68k/kernel/traps.c linux-2.5.65-bk2/arch/m68k/kernel/traps.c
--- linux-2.5.65-bk1/arch/m68k/kernel/traps.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/arch/m68k/kernel/traps.c	Mon Mar 31 12:39:50 2003
@@ -303,7 +303,7 @@
 	return res;
 }
 
-/* after an exception in a writeback the stack frame coresponding
+/* after an exception in a writeback the stack frame corresponding
  * to that exception is discarded, set a few bits in the old frame 
  * to simulate what it should look like
  */
@@ -333,7 +333,7 @@
 			fp->un.fmt7.wb2s = 0;
 	}
 
-	/* do the 2nd wb only if the first one was succesful (except for a kernel wb) */
+	/* do the 2nd wb only if the first one was successful (except for a kernel wb) */
 	if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
 		res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
 				       fp->un.fmt7.wb3d);
diff -urN linux-2.5.65-bk1/arch/m68k/mac/baboon.c linux-2.5.65-bk2/arch/m68k/mac/baboon.c
--- linux-2.5.65-bk1/arch/m68k/mac/baboon.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/arch/m68k/mac/baboon.c	Mon Mar 31 12:39:50 2003
@@ -1,5 +1,5 @@
 /*
- * Baboon Custom IC Managment
+ * Baboon Custom IC Management
  *
  * The Baboon custom IC controls the IDE, PCMCIA and media bay on the
  * PowerBook 190. It multiplexes multiple interrupt sources onto the
diff -urN linux-2.5.65-bk1/arch/m68k/mac/iop.c linux-2.5.65-bk2/arch/m68k/mac/iop.c
--- linux-2.5.65-bk1/arch/m68k/mac/iop.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/arch/m68k/mac/iop.c	Mon Mar 31 12:39:50 2003
@@ -236,7 +236,7 @@
 
 /*
  * This is called by the startup code before anything else. Its purpose
- * is to find and initalize the IOPs early in the boot sequence, so that
+ * is to find and initialize the IOPs early in the boot sequence, so that
  * the serial IOP can be placed into bypass mode _before_ we try to
  * initialize the serial console.
  */
diff -urN linux-2.5.65-bk1/arch/m68k/mac/macints.c linux-2.5.65-bk2/arch/m68k/mac/macints.c
--- linux-2.5.65-bk1/arch/m68k/mac/macints.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/arch/m68k/mac/macints.c	Mon Mar 31 12:39:50 2003
@@ -30,7 +30,7 @@
  *		  - slot 0: SCSI interrupt
  *		  - slot 1: Sound interrupt
  *
- * Levels 3-6 vary by machine type. For VIA or RBV Macintohes:
+ * Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
  *
  *	3	- unused (?)
  *
@@ -494,7 +494,7 @@
  * Add an interrupt service routine to an interrupt source.
  * Returns 0 on success.
  *
- * FIXME: You can register interrupts on nonexistant source (ie PSC4 on a
+ * FIXME: You can register interrupts on nonexistent source (ie PSC4 on a
  *        non-PSC machine). We should return -EINVAL in those cases.
  */
  
diff -urN linux-2.5.65-bk1/arch/m68k/math-emu/fp_arith.c linux-2.5.65-bk2/arch/m68k/math-emu/fp_arith.c
--- linux-2.5.65-bk1/arch/m68k/math-emu/fp_arith.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/arch/m68k/math-emu/fp_arith.c	Mon Mar 31 12:39:50 2003
@@ -113,7 +113,7 @@
 	return dest;
 }
 
-/* fp_fsub: Implementes the kernel of the FSUB, FSSUB, and FDSUB
+/* fp_fsub: Implements the kernel of the FSUB, FSSUB, and FDSUB
    instructions.
 
    Remember that the arguments are in assembler-syntax order! */
diff -urN linux-2.5.65-bk1/arch/m68k/mm/memory.c linux-2.5.65-bk2/arch/m68k/mm/memory.c
--- linux-2.5.65-bk1/arch/m68k/mm/memory.c	Mon Mar 17 13:44:18 2003
+++ linux-2.5.65-bk2/arch/m68k/mm/memory.c	Mon Mar 31 12:39:50 2003
@@ -33,7 +33,7 @@
 typedef struct list_head ptable_desc;
 static LIST_HEAD(ptable_list);
 
-#define PD_PTABLE(page) ((ptable_desc *)virt_to_page(page))
+#define PD_PTABLE(page) ((ptable_desc *)&(virt_to_page(page)->list))
 #define PD_PAGE(ptable) (list_entry(ptable, struct page, list))
 #define PD_MARKBITS(dp) (*(unsigned char *)&PD_PAGE(dp)->index)
 
diff -urN linux-2.5.65-bk1/arch/m68k/mm/sun3mmu.c linux-2.5.65-bk2/arch/m68k/mm/sun3mmu.c
--- linux-2.5.65-bk1/arch/m68k/mm/sun3mmu.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/arch/m68k/mm/sun3mmu.c	Mon Mar 31 12:39:50 2003
@@ -92,13 +92,12 @@
 	}
 
 	mmu_emu_init(bootmem_end);
-	
+
 	current->mm = NULL;
 
 	/* memory sizing is a hack stolen from motorola.c..  hope it works for us */
-	zones_size[1] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
-	zones_size[0] = zones_size[1]/2;
-	zones_size[1] -= zones_size[0];
+	zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+	zones_size[1] = 0;
 	
 	free_area_init(zones_size);
 
diff -urN linux-2.5.65-bk1/arch/m68k/q40/q40ints.c linux-2.5.65-bk2/arch/m68k/q40/q40ints.c
--- linux-2.5.65-bk1/arch/m68k/q40/q40ints.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/arch/m68k/q40/q40ints.c	Mon Mar 31 12:39:50 2003
@@ -7,7 +7,7 @@
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
  *
- * .. used to be losely based on bvme6000ints.c
+ * .. used to be loosely based on bvme6000ints.c
  *
  */
 
@@ -127,6 +127,7 @@
 	    printk("warning IRQ 10 and 11 not distinguishable\n");
 	    irq=10;
 	  default:
+	    ;
 	  }
 
 	if (irq<Q40_IRQ_SAMPLE)
@@ -174,6 +175,7 @@
 	    return;
 	  case 11: irq=10;
 	  default:
+	    ;
 	  }
 	
 	if (irq<Q40_IRQ_SAMPLE)
@@ -315,7 +317,7 @@
   unsigned mir, mer;
   int irq,i;
 
- repeat:
+//repeat:
   mir=master_inb(IIRQ_REG);
   if (mir&Q40_IRQ_FRAME_MASK) {
 	  irq_tab[Q40_IRQ_FRAME].count++;
@@ -342,7 +344,7 @@
 				  continue; /* ignore uninited INTs :-( */
 			  }
 			  if ( irq_tab[irq].state & IRQ_INPROGRESS ) {
-				  /* some handlers do sti() for irq latency reasons, */
+				  /* some handlers do local_irq_enable() for irq latency reasons, */
 				  /* however reentering an active irq handler is not permitted */
 #ifdef IP_USE_DISABLE
 				  /* in theory this is the better way to do it because it still */
@@ -439,7 +441,7 @@
 {
   /* disable ISA iqs : only do something if the driver has been
    * verified to be Q40 "compatible" - right now IDE, NE2K
-   * Any driver should not attempt to sleep accross disable_irq !!
+   * Any driver should not attempt to sleep across disable_irq !!
    */
 
   if ( irq>=5 && irq<=15 ) {
diff -urN linux-2.5.65-bk1/arch/m68k/sun3/sun3dvma.c linux-2.5.65-bk2/arch/m68k/sun3/sun3dvma.c
--- linux-2.5.65-bk1/arch/m68k/sun3/sun3dvma.c	Mon Mar 17 13:44:22 2003
+++ linux-2.5.65-bk2/arch/m68k/sun3/sun3dvma.c	Mon Mar 31 12:39:50 2003
@@ -97,7 +97,7 @@
 	printk("end of hole listing...\n");
 	
 }
-#endif DVMA_DEBUG
+#endif /* DVMA_DEBUG */
 
 static inline int refill(void)
 {
diff -urN linux-2.5.65-bk1/arch/m68k/vmlinux-sun3.lds linux-2.5.65-bk2/arch/m68k/vmlinux-sun3.lds
--- linux-2.5.65-bk1/arch/m68k/vmlinux-sun3.lds	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/arch/m68k/vmlinux-sun3.lds	Mon Mar 31 12:39:50 2003
@@ -16,11 +16,12 @@
 	*(.fixup)
 	*(.gnu.warning)
 	} = 0x4e75
+	RODATA
 
   _etext = .;			/* End of text section */
 
   .data : {			/* Data */
-	RODATA
+	*(.data)
 	CONSTRUCTORS
   	. = ALIGN(16);		/* Exception table */
   	__start___ex_table = .;
diff -urN linux-2.5.65-bk1/arch/sparc/kernel/traps.c linux-2.5.65-bk2/arch/sparc/kernel/traps.c
--- linux-2.5.65-bk1/arch/sparc/kernel/traps.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/arch/sparc/kernel/traps.c	Mon Mar 31 12:39:50 2003
@@ -89,6 +89,7 @@
 
 void die_if_kernel(char *str, struct pt_regs *regs)
 {
+	static int die_counter;
 	int count = 0;
 
 	/* Amuse the user. */
@@ -98,7 +99,7 @@
 "              /_| \\__/ |_\\\n"
 "                 \\__U_/\n");
 
-	printk("%s(%d): %s\n", current->comm, current->pid, str);
+	printk("%s(%d): %s [#%d]\n", current->comm, current->pid, str, ++die_counter);
 	show_regs(regs);
 
 	__SAVE; __SAVE; __SAVE; __SAVE;
diff -urN linux-2.5.65-bk1/arch/sparc64/kernel/head.S linux-2.5.65-bk2/arch/sparc64/kernel/head.S
--- linux-2.5.65-bk1/arch/sparc64/kernel/head.S	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/arch/sparc64/kernel/head.S	Mon Mar 31 12:39:50 2003
@@ -671,7 +671,9 @@
 #endif
 
 	/* Kill PROM timer */
-	wr	%g0, 0, %tick_cmpr
+	sethi	%hi(0x80000000), %g1
+	sllx	%g1, 32, %g1
+	wr	%g1, 0, %tick_cmpr
 
 	BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
 
diff -urN linux-2.5.65-bk1/arch/sparc64/kernel/irq.c linux-2.5.65-bk2/arch/sparc64/kernel/irq.c
--- linux-2.5.65-bk1/arch/sparc64/kernel/irq.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/arch/sparc64/kernel/irq.c	Mon Mar 31 12:39:50 2003
@@ -719,12 +719,8 @@
 	 */
 	{
 		unsigned long clr_mask = 1 << irq;
-		unsigned long tick_mask;
+		unsigned long tick_mask = tick_ops->softint_mask;
 
-		if (SPARC64_USE_STICK)
-			tick_mask = (1UL << 16);
-		else
-			tick_mask = (1UL << 0);
 		if ((irq == 14) && (get_softint() & tick_mask)) {
 			irq = 0;
 			clr_mask = tick_mask;
@@ -946,113 +942,6 @@
 	return 0;
 }
 
-/* This is gets the master TICK_INT timer going. */
-void sparc64_init_timers(void (*cfunc)(int, void *, struct pt_regs *),
-			 unsigned long *clock)
-{
-	unsigned long pstate;
-	extern unsigned long timer_tick_offset;
-	int node, err;
-#ifdef CONFIG_SMP
-	extern void smp_tick_init(void);
-#endif
-
-	if (!SPARC64_USE_STICK) {
-		node = linux_cpus[0].prom_node;
-		*clock = prom_getint(node, "clock-frequency");
-	} else {
-		node = prom_root_node;
-		*clock = prom_getint(node, "stick-frequency");
-	}
-	timer_tick_offset = *clock / HZ;
-#ifdef CONFIG_SMP
-	smp_tick_init();
-#endif
-
-	/* Register IRQ handler. */
-	err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC,
-			  "timer", NULL);
-
-	if (err) {
-		prom_printf("Serious problem, cannot register TICK_INT\n");
-		prom_halt();
-	}
-
-	/* Guarentee that the following sequences execute
-	 * uninterrupted.
-	 */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	/* Set things up so user can access tick register for profiling
-	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
-	 * read back of %tick after writing it.
-	 */
-	__asm__ __volatile__(
-	"	sethi	%%hi(0x80000000), %%g1\n"
-	"	ba,pt	%%xcc, 1f\n"
-	"	 sllx	%%g1, 32, %%g1\n"
-	"	.align	64\n"
-	"1:	rd	%%tick, %%g2\n"
-	"	add	%%g2, 6, %%g2\n"
-	"	andn	%%g2, %%g1, %%g2\n"
-	"	wrpr	%%g2, 0, %%tick\n"
-	"	rdpr	%%tick, %%g0"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	/* Workaround for Spitfire Errata (#54 I think??), I discovered
-	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-	 * number 103640.
-	 *
-	 * On Blackbird writes to %tick_cmpr can fail, the
-	 * workaround seems to be to execute the wr instruction
-	 * at the start of an I-cache line, and perform a dummy
-	 * read back from %tick_cmpr right after writing to it. -DaveM
-	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick, %%g1\n"
-	"	ba,pt	%%xcc, 1f\n"
-	"	 add	%%g1, %0, %%g1\n"
-	"	.align	64\n"
-	"1:	wr	%%g1, 0x0, %%tick_cmpr\n"
-	"	rd	%%tick_cmpr, %%g0"
-	: /* no outputs */
-	: "r" (timer_tick_offset)
-	: "g1");
-	} else {
-	/* Let the user get at STICK too. */
-	__asm__ __volatile__(
-	"	sethi	%%hi(0x80000000), %%g1\n"
-	"	sllx	%%g1, 32, %%g1\n"
-	"	rd	%%asr24, %%g2\n"
-	"	andn	%%g2, %%g1, %%g2\n"
-	"	wr	%%g2, 0, %%asr24"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	__asm__ __volatile__(
-	"	rd	%%asr24, %%g1\n"
-	"	add	%%g1, %0, %%g1\n"
-	"	wr	%%g1, 0x0, %%asr25"
-	: /* no outputs */
-	: "r" (timer_tick_offset)
-	: "g1");
-	}
-
-	/* Restore PSTATE_IE. */
-	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-			     : /* no outputs */
-			     : "r" (pstate));
-
-	local_irq_enable();
-}
-
 #ifdef CONFIG_SMP
 static int retarget_one_irq(struct irqaction *p, int goal_cpu)
 {
diff -urN linux-2.5.65-bk1/arch/sparc64/kernel/smp.c linux-2.5.65-bk2/arch/sparc64/kernel/smp.c
--- linux-2.5.65-bk1/arch/sparc64/kernel/smp.c	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/arch/sparc64/kernel/smp.c	Mon Mar 31 12:39:50 2003
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/cache.h>
+#include <linux/jiffies.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -115,7 +116,6 @@
 void __init smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
-	unsigned long pstate;
 	extern int bigkernel;
 	extern unsigned long kern_locked_tte_data;
 
@@ -133,50 +133,6 @@
 
 	cpu_probe();
 
-	/* Guarentee that the following sequences execute
-	 * uninterrupted.
-	 */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	/* Set things up so user can access tick register for profiling
-	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
-	 * read back of %tick after writing it.
-	 */
-	__asm__ __volatile__(
-	"sethi	%%hi(0x80000000), %%g1\n\t"
-	"ba,pt	%%xcc, 1f\n\t"
-	" sllx	%%g1, 32, %%g1\n\t"
-	".align	64\n"
-"1:	rd	%%tick, %%g2\n\t"
-	"add	%%g2, 6, %%g2\n\t"
-	"andn	%%g2, %%g1, %%g2\n\t"
-	"wrpr	%%g2, 0, %%tick\n\t"
-	"rdpr	%%tick, %%g0"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	if (SPARC64_USE_STICK) {
-		/* Let the user get at STICK too. */
-		__asm__ __volatile__(
-			"sethi	%%hi(0x80000000), %%g1\n\t"
-			"sllx	%%g1, 32, %%g1\n\t"
-			"rd	%%asr24, %%g2\n\t"
-			"andn	%%g2, %%g1, %%g2\n\t"
-			"wr	%%g2, 0, %%asr24"
-		: /* no outputs */
-		: /* no inputs */
-		: "g1", "g2");
-	}
-
-	/* Restore PSTATE_IE. */
-	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-			     : /* no outputs */
-			     : "r" (pstate));
-
 	smp_setup_percpu_timer();
 
 	local_irq_enable();
@@ -211,7 +167,7 @@
 
 static unsigned long current_tick_offset;
 
-/* This stick register synchronization scheme is taken entirely from
+/* This tick register synchronization scheme is taken entirely from
  * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit.
  *
  * The only change I've made is to rework it so that the master
@@ -227,16 +183,7 @@
 static spinlock_t itc_sync_lock = SPIN_LOCK_UNLOCKED;
 static unsigned long go[SLAVE + 1];
 
-#define DEBUG_STICK_SYNC	0
-
-static inline unsigned long get_stick(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__("rd	%%asr24, %0"
-			     : "=r" (val));
-	return val;
-}
+#define DEBUG_TICK_SYNC	0
 
 static inline long get_delta (long *rt, long *master)
 {
@@ -245,14 +192,14 @@
 	unsigned long i;
 
 	for (i = 0; i < NUM_ITERS; i++) {
-		t0 = get_stick();
+		t0 = tick_ops->get_tick();
 		go[MASTER] = 1;
 		membar("#StoreLoad");
 		while (!(tm = go[SLAVE]))
 			membar("#LoadLoad");
 		go[SLAVE] = 0;
 		membar("#StoreStore");
-		t1 = get_stick();
+		t1 = tick_ops->get_tick();
 
 		if (t1 - t0 < best_t1 - best_t0)
 			best_t0 = t0, best_t1 = t1, best_tm = tm;
@@ -268,32 +215,11 @@
 	return tcenter - best_tm;
 }
 
-static void adjust_stick(long adj)
-{
-	unsigned long tmp, pstate;
-
-	__asm__ __volatile__(
-		"rdpr	%%pstate, %0\n\t"
-		"ba,pt	%%xcc, 1f\n\t"
-		" wrpr	%0, %4, %%pstate\n\t"
-		".align	16\n\t"
-		"1:nop\n\t"
-		"rd	%%asr24, %1\n\t"
-		"add	%1, %2, %1\n\t"
-		"wr	%1, 0x0, %%asr24\n\t"
-		"add	%1, %3, %1\n\t"
-		"wr	%1, 0x0, %%asr25\n\t"
-		"wrpr	%0, 0x0, %%pstate"
-		: "=&r" (pstate), "=&r" (tmp)
-		: "r" (adj), "r" (current_tick_offset),
-		  "i" (PSTATE_IE));
-}
-
-void smp_synchronize_stick_client(void)
+void smp_synchronize_tick_client(void)
 {
 	long i, delta, adj, adjust_latency = 0, done = 0;
 	unsigned long flags, rt, master_time_stamp, bound;
-#if DEBUG_STICK_SYNC
+#if DEBUG_TICK_SYNC
 	struct {
 		long rt;	/* roundtrip time */
 		long master;	/* master's timestamp */
@@ -323,9 +249,9 @@
 				} else
 					adj = -delta;
 
-				adjust_stick(adj);
+				tick_ops->add_tick(adj, current_tick_offset);
 			}
-#if DEBUG_STICK_SYNC
+#if DEBUG_TICK_SYNC
 			t[i].rt = rt;
 			t[i].master = master_time_stamp;
 			t[i].diff = delta;
@@ -335,25 +261,25 @@
 	}
 	local_irq_restore(flags);
 
-#if DEBUG_STICK_SYNC
+#if DEBUG_TICK_SYNC
 	for (i = 0; i < NUM_ROUNDS; i++)
 		printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n",
 		       t[i].rt, t[i].master, t[i].diff, t[i].lat);
 #endif
 
-	printk(KERN_INFO "CPU %d: synchronized STICK with master CPU (last diff %ld cycles,"
+	printk(KERN_INFO "CPU %d: synchronized TICK with master CPU (last diff %ld cycles,"
 	       "maxerr %lu cycles)\n", smp_processor_id(), delta, rt);
 }
 
-static void smp_start_sync_stick_client(int cpu);
+static void smp_start_sync_tick_client(int cpu);
 
-static void smp_synchronize_one_stick(int cpu)
+static void smp_synchronize_one_tick(int cpu)
 {
 	unsigned long flags, i;
 
 	go[MASTER] = 0;
 
-	smp_start_sync_stick_client(cpu);
+	smp_start_sync_tick_client(cpu);
 
 	/* wait for client to be ready */
 	while (!go[MASTER])
@@ -370,7 +296,7 @@
 				membar("#LoadLoad");
 			go[MASTER] = 0;
 			membar("#StoreStore");
-			go[SLAVE] = get_stick();
+			go[SLAVE] = tick_ops->get_tick();
 			membar("#StoreLoad");
 		}
 	}
@@ -638,11 +564,11 @@
 	/* NOTE: Caller runs local copy on master. */
 }
 
-extern unsigned long xcall_sync_stick;
+extern unsigned long xcall_sync_tick;
 
-static void smp_start_sync_stick_client(int cpu)
+static void smp_start_sync_tick_client(int cpu)
 {
-	smp_cross_call_masked(&xcall_sync_stick,
+	smp_cross_call_masked(&xcall_sync_tick,
 			      0, 0, 0,
 			      (1UL << cpu));
 }
@@ -1118,12 +1044,7 @@
 	 * Check for level 14 softint.
 	 */
 	{
-		unsigned long tick_mask;
-
-		if (SPARC64_USE_STICK)
-			tick_mask = (1UL << 16);
-		else
-			tick_mask = (1UL << 0);
+		unsigned long tick_mask = tick_ops->softint_mask;
 
 		if (!(get_softint() & tick_mask)) {
 			extern void handler_irq(int, struct pt_regs *);
@@ -1159,47 +1080,14 @@
 				     : "=r" (pstate)
 				     : "i" (PSTATE_IE));
 
-		/* Workaround for Spitfire Errata (#54 I think??), I discovered
-		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-		 * number 103640.
-		 *
-		 * On Blackbird writes to %tick_cmpr can fail, the
-		 * workaround seems to be to execute the wr instruction
-		 * at the start of an I-cache line, and perform a dummy
-		 * read back from %tick_cmpr right after writing to it. -DaveM
-		 *
-		 * Just to be anal we add a workaround for Spitfire
-		 * Errata 50 by preventing pipeline bypasses on the
-		 * final read of the %tick register into a compare
-		 * instruction.  The Errata 50 description states
-		 * that %tick is not prone to this bug, but I am not
-		 * taking any chances.
-		 */
-		if (!SPARC64_USE_STICK) {
-		__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-				     "ba,pt	%%xcc, 1f\n\t"
-				     " add	%0, %2, %0\n\t"
-				     ".align	64\n"
-				  "1: wr	%0, 0x0, %%tick_cmpr\n\t"
-				     "rd	%%tick_cmpr, %%g0\n\t"
-				     "rd	%%tick, %1\n\t"
-				     "mov	%1, %1"
-				     : "=&r" (compare), "=r" (tick)
-				     : "r" (current_tick_offset));
-		} else {
-		__asm__ __volatile__("rd	%%asr25, %0\n\t"
-				     "add	%0, %2, %0\n\t"
-				     "wr	%0, 0x0, %%asr25\n\t"
-				     "rd	%%asr24, %1\n\t"
-				     : "=&r" (compare), "=r" (tick)
-				     : "r" (current_tick_offset));
-		}
+		compare = tick_ops->add_compare(current_tick_offset);
+		tick = tick_ops->get_tick();
 
 		/* Restore PSTATE_IE. */
 		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 				     : /* no outputs */
 				     : "r" (pstate));
-	} while (tick >= compare);
+	} while (time_after_eq(tick, compare));
 }
 
 static void __init smp_setup_percpu_timer(void)
@@ -1217,35 +1105,7 @@
 			     : "=r" (pstate)
 			     : "i" (PSTATE_IE));
 
-	/* Workaround for Spitfire Errata (#54 I think??), I discovered
-	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-	 * number 103640.
-	 *
-	 * On Blackbird writes to %tick_cmpr can fail, the
-	 * workaround seems to be to execute the wr instruction
-	 * at the start of an I-cache line, and perform a dummy
-	 * read back from %tick_cmpr right after writing to it. -DaveM
-	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-		"rd	%%tick, %%g1\n\t"
-		"ba,pt	%%xcc, 1f\n\t"
-		" add	%%g1, %0, %%g1\n\t"
-		".align	64\n"
-	"1:	wr	%%g1, 0x0, %%tick_cmpr\n\t"
-		"rd	%%tick_cmpr, %%g0"
-	: /* no outputs */
-	: "r" (current_tick_offset)
-	: "g1");
-	} else {
-	__asm__ __volatile__(
-		"rd	%%asr24, %%g1\n\t"
-		"add	%%g1, %0, %%g1\n\t"
-		"wr	%%g1, 0x0, %%asr25"
-	: /* no outputs */
-	: "r" (current_tick_offset)
-	: "g1");
-	}
+	tick_ops->init_tick(current_tick_offset);
 
 	/* Restore PSTATE_IE. */
 	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
@@ -1314,44 +1174,23 @@
 		     p += (64 / sizeof(unsigned long)))
 			*((volatile unsigned long *)p);
 
-		/* Now the real measurement. */
-		if (!SPARC64_USE_STICK) {
-		__asm__ __volatile__("b,pt	%%xcc, 1f\n\t"
-				     " rd	%%tick, %0\n\t"
-				     ".align	64\n"
-				     "1:\tldx	[%2 + 0x000], %%g1\n\t"
-				     "ldx	[%2 + 0x040], %%g2\n\t"
-				     "ldx	[%2 + 0x080], %%g3\n\t"
-				     "ldx	[%2 + 0x0c0], %%g5\n\t"
-				     "add	%2, 0x100, %2\n\t"
-				     "cmp	%2, %4\n\t"
-				     "bne,pt	%%xcc, 1b\n\t"
-				     " nop\n\t"
-				     "rd	%%tick, %1\n\t"
-				     : "=&r" (tick1), "=&r" (tick2),
-				       "=&r" (flush_base)
-				     : "2" (flush_base),
-				       "r" (flush_base + ecache_size)
-				     : "g1", "g2", "g3", "g5");
-		} else {
-		__asm__ __volatile__("b,pt	%%xcc, 1f\n\t"
-				     " rd	%%asr24, %0\n\t"
-				     ".align	64\n"
-				     "1:\tldx	[%2 + 0x000], %%g1\n\t"
-				     "ldx	[%2 + 0x040], %%g2\n\t"
-				     "ldx	[%2 + 0x080], %%g3\n\t"
-				     "ldx	[%2 + 0x0c0], %%g5\n\t"
-				     "add	%2, 0x100, %2\n\t"
-				     "cmp	%2, %4\n\t"
+		tick1 = tick_ops->get_tick();
+
+		__asm__ __volatile__("1:\n\t"
+				     "ldx	[%0 + 0x000], %%g1\n\t"
+				     "ldx	[%0 + 0x040], %%g2\n\t"
+				     "ldx	[%0 + 0x080], %%g3\n\t"
+				     "ldx	[%0 + 0x0c0], %%g5\n\t"
+				     "add	%0, 0x100, %0\n\t"
+				     "cmp	%0, %2\n\t"
 				     "bne,pt	%%xcc, 1b\n\t"
-				     " nop\n\t"
-				     "rd	%%asr24, %1\n\t"
-				     : "=&r" (tick1), "=&r" (tick2),
-				       "=&r" (flush_base)
-				     : "2" (flush_base),
+				     " nop"
+				     : "=&r" (flush_base)
+				     : "0" (flush_base),
 				       "r" (flush_base + ecache_size)
 				     : "g1", "g2", "g3", "g5");
-		}
+
+		tick2 = tick_ops->get_tick();
 
 		local_irq_restore(flags);
 
@@ -1370,6 +1209,8 @@
 report:
 	/* Convert ticks/sticks to jiffies. */
 	cache_decay_ticks = cacheflush_time / timer_tick_offset;
+	if (cache_decay_ticks < 1)
+		cache_decay_ticks = 1;
 
 	printk("Using heuristic of %ld cycles, %ld ticks.\n",
 	       cacheflush_time, cache_decay_ticks);
@@ -1438,8 +1279,7 @@
 		if (!test_bit(cpu, &cpu_online_map)) {
 			ret = -ENODEV;
 		} else {
-			if (SPARC64_USE_STICK)
-				smp_synchronize_one_stick(cpu);
+			smp_synchronize_one_tick(cpu);
 		}
 	}
 	return ret;
diff -urN linux-2.5.65-bk1/arch/sparc64/kernel/sparc64_ksyms.c linux-2.5.65-bk2/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.5.65-bk1/arch/sparc64/kernel/sparc64_ksyms.c	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/arch/sparc64/kernel/sparc64_ksyms.c	Mon Mar 31 12:39:50 2003
@@ -128,20 +128,13 @@
 #endif
 
 /* Hard IRQ locking */
-#ifdef CONFIG_SMP
 EXPORT_SYMBOL(synchronize_irq);
-#endif
 
 #if defined(CONFIG_MCOUNT)
 extern void mcount(void);
 EXPORT_SYMBOL_NOVERS(mcount);
 #endif
 
-/* Uniprocessor clock frequency */
-#ifndef CONFIG_SMP
-EXPORT_SYMBOL(up_clock_tick);
-#endif
-
 /* Per-CPU information table */
 EXPORT_SYMBOL(cpu_data);
 
@@ -162,10 +155,13 @@
 EXPORT_SYMBOL(_do_write_unlock);
 #endif
 
-#ifdef CONFIG_SMP
 EXPORT_SYMBOL(smp_call_function);
-#endif
+#endif /* CONFIG_SMP */
 
+/* Uniprocessor clock frequency */
+#ifndef CONFIG_SMP
+extern unsigned long up_clock_tick;
+EXPORT_SYMBOL(up_clock_tick);
 #endif
 
 /* semaphores */
diff -urN linux-2.5.65-bk1/arch/sparc64/kernel/time.c linux-2.5.65-bk2/arch/sparc64/kernel/time.c
--- linux-2.5.65-bk1/arch/sparc64/kernel/time.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/arch/sparc64/kernel/time.c	Mon Mar 31 12:39:50 2003
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/profile.h>
 #include <linux/bcd.h>
+#include <linux/jiffies.h>
 
 #include <asm/oplib.h>
 #include <asm/mostek.h>
@@ -37,6 +38,7 @@
 #include <asm/ebus.h>
 #include <asm/isa.h>
 #include <asm/starfire.h>
+#include <asm/smp.h>
 
 spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
@@ -54,6 +56,352 @@
 
 static int set_rtc_mmss(unsigned long);
 
+struct sparc64_tick_ops *tick_ops;
+
+#define TICK_PRIV_BIT	(1UL << 63)
+
+static void tick_disable_protection(void)
+{
+	/* Set things up so user can access tick register for profiling
+	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
+	 * read back of %tick after writing it.
+	 */
+	__asm__ __volatile__(
+	"	ba,pt	%%xcc, 1f\n"
+	"	 nop\n"
+	"	.align	64\n"
+	"1:	rd	%%tick, %%g2\n"
+	"	add	%%g2, 6, %%g2\n"
+	"	andn	%%g2, %0, %%g2\n"
+	"	wrpr	%%g2, 0, %%tick\n"
+	"	rdpr	%%tick, %%g0"
+	: /* no outputs */
+	: "r" (TICK_PRIV_BIT)
+	: "g2");
+}
+
+static void tick_init_tick(unsigned long offset)
+{
+	tick_disable_protection();
+
+	__asm__ __volatile__(
+	"	rd	%%tick, %%g1\n"
+	"	andn	%%g1, %1, %%g1\n"
+	"	ba,pt	%%xcc, 1f\n"
+	"	 add	%%g1, %0, %%g1\n"
+	"	.align	64\n"
+	"1:	wr	%%g1, 0x0, %%tick_cmpr\n"
+	"	rd	%%tick_cmpr, %%g0"
+	: /* no outputs */
+	: "r" (offset), "r" (TICK_PRIV_BIT)
+	: "g1");
+}
+
+static unsigned long tick_get_tick(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%tick, %0\n\t"
+			     "mov	%0, %0"
+			     : "=r" (ret));
+
+	return ret & ~TICK_PRIV_BIT;
+}
+
+static unsigned long tick_get_compare(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+			     "mov	%0, %0"
+			     : "=r" (ret));
+
+	return ret;
+}
+
+static unsigned long tick_add_compare(unsigned long adj)
+{
+	unsigned long new_compare;
+
+	/* Workaround for Spitfire Errata (#54 I think??), I discovered
+	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+	 * number 103640.
+	 *
+	 * On Blackbird writes to %tick_cmpr can fail, the
+	 * workaround seems to be to execute the wr instruction
+	 * at the start of an I-cache line, and perform a dummy
+	 * read back from %tick_cmpr right after writing to it. -DaveM
+	 */
+	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+			     "ba,pt	%%xcc, 1f\n\t"
+			     " add	%0, %1, %0\n\t"
+			     ".align	64\n"
+			     "1:\n\t"
+			     "wr	%0, 0, %%tick_cmpr\n\t"
+			     "rd	%%tick_cmpr, %%g0"
+			     : "=&r" (new_compare)
+			     : "r" (adj));
+
+	return new_compare;
+}
+
+static unsigned long tick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long new_tick, tmp;
+
+	/* Also need to handle Blackbird bug here too. */
+	__asm__ __volatile__("rd	%%tick, %0\n\t"
+			     "add	%0, %2, %0\n\t"
+			     "wrpr	%0, 0, %%tick\n\t"
+			     "andn	%0, %4, %1\n\t"
+			     "ba,pt	%%xcc, 1f\n\t"
+			     " add	%1, %3, %1\n\t"
+			     ".align	64\n"
+			     "1:\n\t"
+			     "wr	%1, 0, %%tick_cmpr\n\t"
+			     "rd	%%tick_cmpr, %%g0"
+			     : "=&r" (new_tick), "=&r" (tmp)
+			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+
+	return new_tick;
+}
+
+static struct sparc64_tick_ops tick_operations = {
+	.init_tick	=	tick_init_tick,
+	.get_tick	=	tick_get_tick,
+	.get_compare	=	tick_get_compare,
+	.add_tick	=	tick_add_tick,
+	.add_compare	=	tick_add_compare,
+	.softint_mask	=	1UL << 0,
+};
+
+static void stick_init_tick(unsigned long offset)
+{
+	tick_disable_protection();
+
+	/* Let the user get at STICK too. */
+	__asm__ __volatile__(
+	"	rd	%%asr24, %%g2\n"
+	"	andn	%%g2, %0, %%g2\n"
+	"	wr	%%g2, 0, %%asr24"
+	: /* no outputs */
+	: "r" (TICK_PRIV_BIT)
+	: "g1", "g2");
+
+	__asm__ __volatile__(
+	"	rd	%%asr24, %%g1\n"
+	"	andn	%%g1, %1, %%g1\n"
+	"	add	%%g1, %0, %%g1\n"
+	"	wr	%%g1, 0x0, %%asr25"
+	: /* no outputs */
+	: "r" (offset), "r" (TICK_PRIV_BIT)
+	: "g1");
+}
+
+static unsigned long stick_get_tick(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%asr24, %0"
+			     : "=r" (ret));
+
+	return ret & ~TICK_PRIV_BIT;
+}
+
+static unsigned long stick_get_compare(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%asr25, %0"
+			     : "=r" (ret));
+
+	return ret;
+}
+
+static unsigned long stick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long new_tick, tmp;
+
+	__asm__ __volatile__("rd	%%asr24, %0\n\t"
+			     "add	%0, %2, %0\n\t"
+			     "wr	%0, 0, %%asr24\n\t"
+			     "andn	%0, %4, %1\n\t"
+			     "add	%1, %3, %1\n\t"
+			     "wr	%1, 0, %%asr25"
+			     : "=&r" (new_tick), "=&r" (tmp)
+			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+
+	return new_tick;
+}
+
+static unsigned long stick_add_compare(unsigned long adj)
+{
+	unsigned long new_compare;
+
+	__asm__ __volatile__("rd	%%asr25, %0\n\t"
+			     "add	%0, %1, %0\n\t"
+			     "wr	%0, 0, %%asr25"
+			     : "=&r" (new_compare)
+			     : "r" (adj));
+
+	return new_compare;
+}
+
+static struct sparc64_tick_ops stick_operations = {
+	.init_tick	=	stick_init_tick,
+	.get_tick	=	stick_get_tick,
+	.get_compare	=	stick_get_compare,
+	.add_tick	=	stick_add_tick,
+	.add_compare	=	stick_add_compare,
+	.softint_mask	=	1UL << 16,
+};
+
+/* On Hummingbird the STICK/STICK_CMPR register is implemented
+ * in I/O space.  There are two 64-bit registers each, the
+ * first holds the low 32-bits of the value and the second holds
+ * the high 32-bits.
+ *
+ * Since STICK is constantly updating, we have to access it carefully.
+ *
+ * The sequence we use to read is:
+ * 1) read low
+ * 2) read high
+ * 3) read low again, if it rolled over increment high by 1
+ *
+ * Writing STICK safely is also tricky:
+ * 1) write low to zero
+ * 2) write high
+ * 3) write low
+ */
+#define HBIRD_STICKCMP_ADDR	0x1fe0000f060UL
+#define HBIRD_STICK_ADDR	0x1fe0000f070UL
+
+static unsigned long __hbird_read_stick(void)
+{
+	unsigned long ret, tmp1, tmp2, tmp3;
+	unsigned long addr = HBIRD_STICK_ADDR;
+
+	__asm__ __volatile__("ldxa	[%1] %5, %2\n\t"
+			     "add	%1, 0x8, %1\n\t"
+			     "ldxa	[%1] %5, %3\n\t"
+			     "sub	%1, 0x8, %1\n\t"
+			     "ldxa	[%1] %5, %4\n\t"
+			     "cmp	%4, %2\n\t"
+			     "blu,a,pn	%%xcc, 1f\n\t"
+			     " add	%3, 1, %3\n"
+			     "1:\n\t"
+			     "sllx	%3, 32, %3\n\t"
+			     "or	%3, %4, %0\n\t"
+			     : "=&r" (ret), "=&r" (addr),
+			       "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3)
+			     : "i" (ASI_PHYS_BYPASS_EC_E), "1" (addr));
+
+	return ret;
+}
+
+static unsigned long __hbird_read_compare(void)
+{
+	unsigned long low, high;
+	unsigned long addr = HBIRD_STICKCMP_ADDR;
+
+	__asm__ __volatile__("ldxa	[%2] %3, %0\n\t"
+			     "add	%2, 0x8, %2\n\t"
+			     "ldxa	[%2] %3, %1"
+			     : "=&r" (low), "=&r" (high), "=&r" (addr)
+			     : "i" (ASI_PHYS_BYPASS_EC_E), "2" (addr));
+
+	return (high << 32UL) | low;
+}
+
+static void __hbird_write_stick(unsigned long val)
+{
+	unsigned long low = (val & 0xffffffffUL);
+	unsigned long high = (val >> 32UL);
+	unsigned long addr = HBIRD_STICK_ADDR;
+
+	__asm__ __volatile__("stxa	%%g0, [%0] %4\n\t"
+			     "add	%0, 0x8, %0\n\t"
+			     "stxa	%3, [%0] %4\n\t"
+			     "sub	%0, 0x8, %0\n\t"
+			     "stxa	%2, [%0] %4"
+			     : "=&r" (addr)
+			     : "0" (addr), "r" (low), "r" (high),
+			       "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+static void __hbird_write_compare(unsigned long val)
+{
+	unsigned long low = (val & 0xffffffffUL);
+	unsigned long high = (val >> 32UL);
+	unsigned long addr = HBIRD_STICKCMP_ADDR + 0x8UL;
+
+	__asm__ __volatile__("stxa	%3, [%0] %4\n\t"
+			     "sub	%0, 0x8, %0\n\t"
+			     "stxa	%2, [%0] %4"
+			     : "=&r" (addr)
+			     : "0" (addr), "r" (low), "r" (high),
+			       "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+static void hbtick_init_tick(unsigned long offset)
+{
+	unsigned long val;
+
+	tick_disable_protection();
+
+	/* XXX This seems to be necessary to 'jumpstart' Hummingbird
+	 * XXX into actually sending STICK interrupts.  I think because
+	 * XXX of how we store %tick_cmpr in head.S this somehow resets the
+	 * XXX {TICK + STICK} interrupt mux.  -DaveM
+	 */
+	__hbird_write_stick(__hbird_read_stick());
+
+	val = __hbird_read_stick() & ~TICK_PRIV_BIT;
+	__hbird_write_compare(val + offset);
+}
+
+static unsigned long hbtick_get_tick(void)
+{
+	return __hbird_read_stick() & ~TICK_PRIV_BIT;
+}
+
+static unsigned long hbtick_get_compare(void)
+{
+	return __hbird_read_compare();
+}
+
+static unsigned long hbtick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long val;
+
+	val = __hbird_read_stick() + adj;
+	__hbird_write_stick(val);
+
+	val &= ~TICK_PRIV_BIT;
+	__hbird_write_compare(val + offset);
+
+	return val;
+}
+
+static unsigned long hbtick_add_compare(unsigned long adj)
+{
+	unsigned long val = __hbird_read_compare() + adj;
+
+	val &= ~TICK_PRIV_BIT;
+	__hbird_write_compare(val);
+
+	return val;
+}
+
+static struct sparc64_tick_ops hbtick_operations = {
+	.init_tick	=	hbtick_init_tick,
+	.get_tick	=	hbtick_get_tick,
+	.get_compare	=	hbtick_get_compare,
+	.add_tick	=	hbtick_add_tick,
+	.add_compare	=	hbtick_add_compare,
+	.softint_mask	=	1UL << 0,
+};
+
 /* timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  *
@@ -62,7 +410,8 @@
  */
 unsigned long timer_tick_offset;
 unsigned long timer_tick_compare;
-unsigned long timer_ticks_per_usec_quotient;
+
+static unsigned long timer_ticks_per_usec_quotient;
 
 #define TICK_SIZE (tick_nsec / 1000)
 
@@ -146,49 +495,14 @@
 				     : "=r" (pstate)
 				     : "i" (PSTATE_IE));
 
-		/* Workaround for Spitfire Errata (#54 I think??), I discovered
-		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-		 * number 103640.
-		 *
-		 * On Blackbird writes to %tick_cmpr can fail, the
-		 * workaround seems to be to execute the wr instruction
-		 * at the start of an I-cache line, and perform a dummy
-		 * read back from %tick_cmpr right after writing to it. -DaveM
-		 *
-		 * Just to be anal we add a workaround for Spitfire
-		 * Errata 50 by preventing pipeline bypasses on the
-		 * final read of the %tick register into a compare
-		 * instruction.  The Errata 50 description states
-		 * that %tick is not prone to this bug, but I am not
-		 * taking any chances.
-		 */
-		if (!SPARC64_USE_STICK) {
-		__asm__ __volatile__(
-		"	rd	%%tick_cmpr, %0\n"
-		"	ba,pt	%%xcc, 1f\n"
-		"	 add	%0, %2, %0\n"
-		"	.align	64\n"
-		"1: 	wr	%0, 0, %%tick_cmpr\n"
-		"	rd	%%tick_cmpr, %%g0\n"
-		"	rd	%%tick, %1\n"
-		"	mov	%1, %1"
-			: "=&r" (timer_tick_compare), "=r" (ticks)
-			: "r" (timer_tick_offset));
-		} else {
-		__asm__ __volatile__(
-		"	rd	%%asr25, %0\n"
-		"	add	%0, %2, %0\n"
-		"	wr	%0, 0, %%asr25\n"
-		"	rd	%%asr24, %1"
-			: "=&r" (timer_tick_compare), "=r" (ticks)
-			: "r" (timer_tick_offset));
-		}
+		timer_tick_compare = tick_ops->add_compare(timer_tick_offset);
+		ticks = tick_ops->get_tick();
 
 		/* Restore PSTATE_IE. */
 		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 				     : /* no outputs */
 				     : "r" (pstate));
-	} while (ticks >= timer_tick_compare);
+	} while (time_after_eq(ticks, timer_tick_compare));
 
 	timer_check_rtc();
 
@@ -205,19 +519,7 @@
 	/*
 	 * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
 	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick_cmpr, %0\n"
-	"	add	%0, %1, %0"
-		: "=&r" (timer_tick_compare)
-		: "r" (timer_tick_offset));
-	} else {
-	__asm__ __volatile__(
-	"	rd	%%asr25, %0\n"
-	"	add	%0, %1, %0"
-		: "=&r" (timer_tick_compare)
-		: "r" (timer_tick_offset));
-	}
+	timer_tick_compare = tick_ops->get_compare() + timer_tick_offset;
 
 	timer_check_rtc();
 
@@ -620,40 +922,90 @@
 	local_irq_restore(flags);
 }
 
-void __init time_init(void)
+/* This is gets the master TICK_INT timer going. */
+static unsigned long sparc64_init_timers(void (*cfunc)(int, void *, struct pt_regs *))
 {
-	/* clock_probe() is now done at end of [se]bus_init on sparc64
-	 * so that sbus, fhc and ebus bus information is probed and
-	 * available.
+	unsigned long pstate, clock;
+	int node, err;
+#ifdef CONFIG_SMP
+	extern void smp_tick_init(void);
+#endif
+
+	if (tlb_type == spitfire) {
+		unsigned long ver, manuf, impl;
+
+		__asm__ __volatile__ ("rdpr %%ver, %0"
+				      : "=&r" (ver));
+		manuf = ((ver >> 48) & 0xffff);
+		impl = ((ver >> 32) & 0xffff);
+		if (manuf == 0x17 && impl == 0x13) {
+			/* Hummingbird, aka Ultra-IIe */
+			tick_ops = &hbtick_operations;
+			node = prom_root_node;
+			clock = prom_getint(node, "stick-frequency");
+		} else {
+			tick_ops = &tick_operations;
+			node = linux_cpus[0].prom_node;
+			clock = prom_getint(node, "clock-frequency");
+		}
+	} else {
+		tick_ops = &stick_operations;
+		node = prom_root_node;
+		clock = prom_getint(node, "stick-frequency");
+	}
+	timer_tick_offset = clock / HZ;
+
+#ifdef CONFIG_SMP
+	smp_tick_init();
+#endif
+
+	/* Register IRQ handler. */
+	err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC,
+			  "timer", NULL);
+
+	if (err) {
+		prom_printf("Serious problem, cannot register TICK_INT\n");
+		prom_halt();
+	}
+
+	/* Guarentee that the following sequences execute
+	 * uninterrupted.
 	 */
-	unsigned long clock;
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+
+	tick_ops->init_tick(timer_tick_offset);
+
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+			     : /* no outputs */
+			     : "r" (pstate));
+
+	local_irq_enable();
 
-	sparc64_init_timers(timer_interrupt, &clock);
-	timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
+	return clock;
+}
+
+/* The quotient formula is taken from the IA64 port. */
+void __init time_init(void)
+{
+	unsigned long clock = sparc64_init_timers(timer_interrupt);
+
+	timer_ticks_per_usec_quotient =
+		(((1000000UL << 30) +
+		  (clock / 2)) / clock);
 }
 
 static __inline__ unsigned long do_gettimeoffset(void)
 {
-	unsigned long ticks;
+	unsigned long ticks = tick_ops->get_tick();
 
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick, %%g1\n"
-	"	add	%1, %%g1, %0\n"
-	"	sub	%0, %2, %0\n"
-		: "=r" (ticks)
-		: "r" (timer_tick_offset), "r" (timer_tick_compare)
-		: "g1", "g2");
-	} else {
-	__asm__ __volatile__("rd	%%asr24, %%g1\n\t"
-			     "add	%1, %%g1, %0\n\t"
-			     "sub	%0, %2, %0\n\t"
-			     : "=&r" (ticks)
-			     : "r" (timer_tick_offset), "r" (timer_tick_compare)
-			     : "g1");
-	}
+	ticks += timer_tick_offset;
+	ticks -= timer_tick_compare;
 
-	return (ticks * timer_ticks_per_usec_quotient) >> 32UL;
+	return (ticks * timer_ticks_per_usec_quotient) >> 30UL;
 }
 
 void do_settimeofday(struct timeval *tv)
diff -urN linux-2.5.65-bk1/arch/sparc64/kernel/trampoline.S linux-2.5.65-bk2/arch/sparc64/kernel/trampoline.S
--- linux-2.5.65-bk1/arch/sparc64/kernel/trampoline.S	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/arch/sparc64/kernel/trampoline.S	Mon Mar 31 12:39:50 2003
@@ -85,7 +85,10 @@
 
 startup_continue:
 	wrpr		%g0, 15, %pil
-	wr		%g0, 0, %tick_cmpr
+
+	sethi		%hi(0x80000000), %g2
+	sllx		%g2, 32, %g2
+	wr		%g2, 0, %tick_cmpr
 
 	/* Call OBP by hand to lock KERNBASE into i/d tlbs. */
 	mov		%o0, %l0
diff -urN linux-2.5.65-bk1/arch/sparc64/kernel/traps.c linux-2.5.65-bk2/arch/sparc64/kernel/traps.c
--- linux-2.5.65-bk1/arch/sparc64/kernel/traps.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/arch/sparc64/kernel/traps.c	Mon Mar 31 12:39:50 2003
@@ -33,6 +33,7 @@
 #include <asm/chafsr.h>
 #include <asm/psrcompat.h>
 #include <asm/processor.h>
+#include <asm/timer.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
@@ -588,7 +589,7 @@
 	flush_linesize = ecache_flush_linesize;
 	flush_size = ecache_flush_size >> 1;
 
-	__asm__ __volatile__("rd %%tick, %0" : "=r" (tick1));
+	tick1 = tick_ops->get_tick();
 
 	__asm__ __volatile__("1: subcc	%0, %4, %0\n\t"
 			     "   bne,pt	%%xcc, 1b\n\t"
@@ -597,7 +598,7 @@
 			     : "0" (flush_size), "r" (flush_base),
 			       "i" (ASI_PHYS_USE_EC), "r" (flush_linesize));
 
-	__asm__ __volatile__("rd %%tick, %0" : "=r" (tick2));
+	tick2 = tick_ops->get_tick();
 
 	raw = (tick2 - tick1);
 
@@ -1598,6 +1599,7 @@
 
 void die_if_kernel(char *str, struct pt_regs *regs)
 {
+	static int die_counter;
 	extern void __show_regs(struct pt_regs * regs);
 	extern void smp_report_regs(void);
 	int count = 0;
@@ -1610,7 +1612,7 @@
 "              /_| \\__/ |_\\\n"
 "                 \\__U_/\n");
 
-	printk("%s(%d): %s\n", current->comm, current->pid, str);
+	printk("%s(%d): %s [#%d]\n", current->comm, current->pid, str, ++die_counter);
 	__asm__ __volatile__("flushw");
 	__show_regs(regs);
 	if (regs->tstate & TSTATE_PRIV) {
diff -urN linux-2.5.65-bk1/arch/sparc64/mm/ultra.S linux-2.5.65-bk2/arch/sparc64/mm/ultra.S
--- linux-2.5.65-bk1/arch/sparc64/mm/ultra.S	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/arch/sparc64/mm/ultra.S	Mon Mar 31 12:39:50 2003
@@ -560,8 +560,8 @@
 	/* This runs in a very controlled environment, so we do
 	 * not need to worry about BH races etc.
 	 */
-	.globl		xcall_sync_stick
-xcall_sync_stick:
+	.globl		xcall_sync_tick
+xcall_sync_tick:
 	rdpr		%pstate, %g2
 	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
 	rdpr		%pil, %g2
@@ -569,7 +569,7 @@
 	sethi		%hi(109f), %g7
 	b,pt		%xcc, etrap_irq
 109:	 or		%g7, %lo(109b), %g7
-	call		smp_synchronize_stick_client
+	call		smp_synchronize_tick_client
 	 nop
 	clr		%l6
 	b		rtrap_xcall
diff -urN linux-2.5.65-bk1/arch/x86_64/kernel/irq.c linux-2.5.65-bk2/arch/x86_64/kernel/irq.c
--- linux-2.5.65-bk1/arch/x86_64/kernel/irq.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/arch/x86_64/kernel/irq.c	Mon Mar 31 12:39:50 2003
@@ -732,6 +732,9 @@
 	struct irqaction *old, **p;
 	irq_desc_t *desc = irq_desc + irq;
 
+	if (desc->handler == &no_irq_type)
+		return -ENOSYS;
+
 	/*
 	 * Some drivers like serial.c use request_irq() heavily,
 	 * so we have to be careful not to interfere with a
diff -urN linux-2.5.65-bk1/drivers/acpi/processor.c linux-2.5.65-bk2/drivers/acpi/processor.c
--- linux-2.5.65-bk1/drivers/acpi/processor.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/drivers/acpi/processor.c	Mon Mar 31 12:39:50 2003
@@ -1356,7 +1356,8 @@
         loff_t			*data)
 {
 	int			result = 0;
-	struct acpi_processor	*pr = (struct acpi_processor *) data;
+        struct seq_file 	*m = (struct seq_file *)file->private_data;
+	struct acpi_processor	*pr = (struct acpi_processor *)m->private;
 	char			state_string[12] = {'\0'};
 
 	ACPI_FUNCTION_TRACE("acpi_processor_write_throttling");
@@ -1418,7 +1419,8 @@
 	loff_t			*data)
 {
 	int			result = 0;
-	struct acpi_processor	*pr = (struct acpi_processor *) data;
+        struct seq_file 	*m = (struct seq_file *)file->private_data;
+	struct acpi_processor	*pr = (struct acpi_processor *)m->private;
 	char			limit_string[25] = {'\0'};
 	int			px = 0;
 	int			tx = 0;
diff -urN linux-2.5.65-bk1/drivers/atm/idt77252.c linux-2.5.65-bk2/drivers/atm/idt77252.c
--- linux-2.5.65-bk1/drivers/atm/idt77252.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/atm/idt77252.c	Mon Mar 31 12:39:50 2003
@@ -730,7 +730,7 @@
 		struct atm_vcc *vcc = vc->tx_vcc;
 
 		vc->estimator->cells += (skb->len + 47) / 48;
-		if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) {
+		if (atomic_read(&vcc->sk->wmem_alloc) > (vcc->sk->sndbuf >> 1)) {
 			u32 cps = vc->estimator->maxcps;
 
 			vc->estimator->cps = cps;
@@ -2025,7 +2025,7 @@
 		atomic_inc(&vcc->stats->tx_err);
 		return -ENOMEM;
 	}
-	atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
+	atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
 	ATM_SKB(skb)->iovcnt = 0;
 
 	memcpy(skb_put(skb, 52), cell, 52);
diff -urN linux-2.5.65-bk1/drivers/block/amiflop.c linux-2.5.65-bk2/drivers/block/amiflop.c
--- linux-2.5.65-bk1/drivers/block/amiflop.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/block/amiflop.c	Mon Mar 31 12:39:50 2003
@@ -353,10 +353,8 @@
 		unit[nr].motor = 1;
 		fd_select(nr);
 
-		del_timer(&motor_on_timer);
 		motor_on_timer.data = nr;
-		motor_on_timer.expires = jiffies + HZ/2;
-		add_timer(&motor_on_timer);
+		mod_timer(&motor_on_timer, jiffies + HZ/2);
 
 		on_attempts = 10;
 		sleep_on (&motor_wait);
@@ -414,11 +412,9 @@
 	int drive;
 
 	drive = nr & 3;
-	del_timer(motor_off_timer + drive);
-	motor_off_timer[drive].expires = jiffies + 3*HZ;
 	/* called this way it is always from interrupt */
 	motor_off_timer[drive].data = nr | 0x80000000;
-	add_timer(motor_off_timer + nr);
+	mod_timer(motor_off_timer + drive, jiffies + 3*HZ);
 }
 
 static int fd_calibrate(int drive)
@@ -1429,10 +1425,7 @@
 
 			floppy->dirty = 1;
 		        /* reset the timer */
-		        del_timer (flush_track_timer + drive);
-			    
-			flush_track_timer[drive].expires = jiffies + 1;
-			add_timer (flush_track_timer + drive);
+			mod_timer (flush_track_timer + drive, jiffies + 1);
 			local_irq_restore(flags);
 			break;
 		}
diff -urN linux-2.5.65-bk1/drivers/block/cciss.c linux-2.5.65-bk2/drivers/block/cciss.c
--- linux-2.5.65-bk1/drivers/block/cciss.c	Mon Mar 17 13:44:46 2003
+++ linux-2.5.65-bk2/drivers/block/cciss.c	Mon Mar 31 12:39:50 2003
@@ -2623,12 +2623,8 @@
 {
 	printk(KERN_INFO DRIVER_NAME "\n");
 
-	/* Register for out PCI devices */
-	if (pci_register_driver(&cciss_pci_driver) > 0 )
-		return 0;
-	else 
-		return -ENODEV;
-
+	/* Register for our PCI devices */
+	return pci_register_driver(&cciss_pci_driver);
 }
 
 static int __init init_cciss_module(void)
diff -urN linux-2.5.65-bk1/drivers/block/floppy.c linux-2.5.65-bk2/drivers/block/floppy.c
--- linux-2.5.65-bk1/drivers/block/floppy.c	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/drivers/block/floppy.c	Mon Mar 31 12:39:50 2003
@@ -3649,6 +3649,8 @@
 				name = default_drive_params[type].name;
 				allowed_drive_mask |= 1 << drive;
 			}
+			else
+				allowed_drive_mask &= ~(1 << drive);
 		} else {
 			params = &default_drive_params[0].params;
 			sprintf(temparea, "unknown type %d (usb?)", type);
diff -urN linux-2.5.65-bk1/drivers/block/nbd.c linux-2.5.65-bk2/drivers/block/nbd.c
--- linux-2.5.65-bk1/drivers/block/nbd.c	Mon Mar 17 13:43:47 2003
+++ linux-2.5.65-bk2/drivers/block/nbd.c	Mon Mar 31 12:39:50 2003
@@ -76,22 +76,15 @@
 {
 	int uptodate = (req->errors == 0) ? 1 : 0;
 	request_queue_t *q = req->q;
-	struct bio *bio;
-	unsigned nsect;
 	unsigned long flags;
 
 #ifdef PARANOIA
 	requests_out++;
 #endif
 	spin_lock_irqsave(q->queue_lock, flags);
-	while((bio = req->bio) != NULL) {
-		nsect = bio_sectors(bio);
-		blk_finished_io(nsect);
-		req->bio = bio->bi_next;
-		bio->bi_next = NULL;
-		bio_endio(bio, nsect << 9, uptodate ? 0 : -EIO);
+	if (!end_that_request_first(req, uptodate, req->nr_sectors)) {
+		end_that_request_last(req);
 	}
-	blk_put_request(req);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
@@ -243,7 +236,7 @@
 		req = list_entry(tmp, struct request, queuelist);
 		if (req != xreq)
 			continue;
-		list_del(&req->queuelist);
+		list_del_init(&req->queuelist);
 		spin_unlock(&lo->queue_lock);
 		return req;
 	}
@@ -322,7 +315,7 @@
 		spin_lock(&lo->queue_lock);
 		if (!list_empty(&lo->queue_head)) {
 			req = list_entry(lo->queue_head.next, struct request, queuelist);
-			list_del(&req->queuelist);
+			list_del_init(&req->queuelist);
 		}
 		spin_unlock(&lo->queue_lock);
 		if (req) {
@@ -387,7 +380,7 @@
 		if (req->errors) {
 			printk(KERN_ERR "nbd: nbd_send_req failed\n");
 			spin_lock(&lo->queue_lock);
-			list_del(&req->queuelist);
+			list_del_init(&req->queuelist);
 			spin_unlock(&lo->queue_lock);
 			nbd_end_request(req);
 			spin_lock_irq(q->queue_lock);
@@ -590,6 +583,7 @@
 		disk->first_minor = i;
 		disk->fops = &nbd_fops;
 		disk->private_data = &nbd_dev[i];
+		disk->queue = &nbd_queue;
 		sprintf(disk->disk_name, "nbd%d", i);
 		set_capacity(disk, 0x3ffffe);
 		add_disk(disk);
diff -urN linux-2.5.65-bk1/drivers/cdrom/cdrom.c linux-2.5.65-bk2/drivers/cdrom/cdrom.c
--- linux-2.5.65-bk1/drivers/cdrom/cdrom.c	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/drivers/cdrom/cdrom.c	Mon Mar 31 12:39:50 2003
@@ -1125,7 +1125,7 @@
 
 static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
 {
-	unsigned char buf[20], *base;
+	unsigned char buf[21], *base;
 	struct dvd_layer *layer;
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
diff -urN linux-2.5.65-bk1/drivers/cdrom/cdu31a.c linux-2.5.65-bk2/drivers/cdrom/cdu31a.c
--- linux-2.5.65-bk1/drivers/cdrom/cdu31a.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/drivers/cdrom/cdu31a.c	Mon Mar 31 12:39:50 2003
@@ -1375,9 +1375,9 @@
 			       readahead_buffer + (2048 -
 						   readahead_dataleft),
 			       readahead_dataleft);
-			readahead_dataleft = 0;
 			bytesleft -= readahead_dataleft;
 			offset += readahead_dataleft;
+			readahead_dataleft = 0;
 		} else {
 			/* The readahead will fill the whole buffer, get the data
 			   and return. */
diff -urN linux-2.5.65-bk1/drivers/char/amiserial.c linux-2.5.65-bk2/drivers/char/amiserial.c
--- linux-2.5.65-bk1/drivers/char/amiserial.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/drivers/char/amiserial.c	Mon Mar 31 12:39:50 2003
@@ -102,8 +102,6 @@
 
 static char *serial_name = "Amiga-builtin serial driver";
 
-static DECLARE_TASK_QUEUE(tq_serial);
-
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
 
@@ -276,8 +274,7 @@
 				  int event)
 {
 	info->event |= 1 << event;
-	queue_task(&info->tqueue, &tq_serial);
-	mark_bh(SERIAL_BH);
+	tasklet_schedule(&info->tlet);
 }
 
 static _INLINE_ void receive_chars(struct async_struct *info)
@@ -560,12 +557,8 @@
  * interrupt driver proper are done; the interrupt driver schedules
  * them using rs_sched_event(), and they get done here.
  */
-static void do_serial_bh(void)
-{
-	run_task_queue(&tq_serial);
-}
 
-static void do_softint(void *private_)
+static void do_softint(unsigned long private_)
 {
 	struct async_struct	*info = (struct async_struct *) private_;
 	struct tty_struct	*tty;
@@ -1878,8 +1871,7 @@
 	info->flags = sstate->flags;
 	info->xmit_fifo_size = sstate->xmit_fifo_size;
 	info->line = line;
-	info->tqueue.routine = do_softint;
-	info->tqueue.data = info;
+	tasklet_init(&info->tlet, do_softint, (unsigned long)info);
 	info->state = sstate;
 	if (sstate->info) {
 		kfree(info);
@@ -2117,8 +2109,6 @@
 	if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, "amiserial [Paula]"))
 		return -EBUSY;
 
-	init_bh(SERIAL_BH, do_serial_bh);
-
 	IRQ_ports = NULL;
 
 	show_serial_version();
@@ -2234,23 +2224,18 @@
 
 static __exit void rs_exit(void) 
 {
-	unsigned long flags;
 	int e1, e2;
-	struct async_struct *info;
+	struct async_struct *info = rs_table[0].info;
 
 	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
-	save_flags(flags);
-	cli();
-        remove_bh(SERIAL_BH);
+	tasklet_kill(&info->tlet);
 	if ((e1 = tty_unregister_driver(&serial_driver)))
 		printk("SERIAL: failed to unregister serial driver (%d)\n",
 		       e1);
 	if ((e2 = tty_unregister_driver(&callout_driver)))
 		printk("SERIAL: failed to unregister callout driver (%d)\n", 
 		       e2);
-	restore_flags(flags);
 
-	info = rs_table[0].info;
 	if (info) {
 	  rs_table[0].info = NULL;
 	  kfree(info);
@@ -2320,9 +2305,10 @@
 /*
  *	Register console.
  */
-static void __init amiserial_console_init(void)
+static int __init amiserial_console_init(void)
 {
 	register_console(&sercons);
+	return 0;
 }
 console_initcall(amiserial_console_init);
 #endif
diff -urN linux-2.5.65-bk1/drivers/char/decserial.c linux-2.5.65-bk2/drivers/char/decserial.c
--- linux-2.5.65-bk1/drivers/char/decserial.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/drivers/char/decserial.c	Mon Mar 31 12:39:50 2003
@@ -75,7 +75,7 @@
 /* serial_console_init handles the special case of starting
  *   up the console on the serial port
  */
-static void __init decserial_console_init(void)
+static int __init decserial_console_init(void)
 {
 #if defined(CONFIG_ZS) && defined(CONFIG_DZ)
     if (IOASIC)
@@ -93,6 +93,7 @@
 #endif
 
 #endif
+    return 0;
 }
 console_initcall(decserial_console_init);
 
diff -urN linux-2.5.65-bk1/drivers/char/drm/i830_dma.c linux-2.5.65-bk2/drivers/char/drm/i830_dma.c
--- linux-2.5.65-bk1/drivers/char/drm/i830_dma.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/drivers/char/drm/i830_dma.c	Mon Mar 31 12:39:50 2003
@@ -40,12 +40,6 @@
 #include <linux/interrupt.h>	/* For task queue support */
 #include <linux/delay.h>
 
-#ifdef DO_MUNMAP_4_ARGS
-#define DO_MUNMAP(m, a, l)	do_munmap(m, a, l, 1)
-#else
-#define DO_MUNMAP(m, a, l)	do_munmap(m, a, l)
-#endif
-
 #define I830_BUF_FREE		2
 #define I830_BUF_CLIENT		1
 #define I830_BUF_HARDWARE      	0
@@ -230,7 +224,7 @@
 		return -EINVAL;
 
 	down_write(&current->mm->mmap_sem);
-	retcode = DO_MUNMAP(current->mm,
+	retcode = do_munmap(current->mm,
 			    (unsigned long)buf_priv->virtual,
 			    (size_t) buf->total);
 	up_write(&current->mm->mmap_sem);
diff -urN linux-2.5.65-bk1/drivers/char/genrtc.c linux-2.5.65-bk2/drivers/char/genrtc.c
--- linux-2.5.65-bk1/drivers/char/genrtc.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/drivers/char/genrtc.c	Mon Mar 31 12:39:50 2003
@@ -1,5 +1,8 @@
 /*
- *	Real Time Clock interface for q40 and other m68k machines
+ *	Real Time Clock interface for
+ *		- q40 and other m68k machines,
+ *		- HP PARISC machines
+ *		- PowerPC machines
  *      emulate some RTC irq capabilities in software
  *
  *      Copyright (C) 1999 Richard Zidlicky
@@ -13,7 +16,7 @@
  *	pseudo-file for status information.
  *
  *	The ioctls can be used to set the interrupt behaviour where
- *  supported.
+ *	supported.
  *
  *	The /dev/rtc interface will block on reads until an interrupt
  *	has been received. If a RTC interrupt has already happened,
@@ -34,9 +37,10 @@
  *      1.04 removed useless timer code       rz@linux-m68k.org
  *      1.05 portable RTC_UIE emulation       rz@linux-m68k.org
  *      1.06 set_rtc_time can return an error trini@kernel.crashing.org
+ *      1.07 ported to HP PARISC (hppa)	      Helge Deller <deller@gmx.de>
  */
 
-#define RTC_VERSION	"1.06"
+#define RTC_VERSION	"1.07"
 
 #include <linux/module.h>
 #include <linux/config.h>
@@ -63,20 +67,17 @@
 
 static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
 
-static int gen_rtc_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg);
-
 /*
  *	Bits in gen_rtc_status.
  */
 
 #define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
 
-unsigned char gen_rtc_status;		/* bitmapped status byte.	*/
-unsigned long gen_rtc_irq_data;		/* our output to the world	*/
+static unsigned char gen_rtc_status;	/* bitmapped status byte.	*/
+static unsigned long gen_rtc_irq_data;	/* our output to the world	*/
 
 /* months start at 0 now */
-unsigned char days_in_mo[] =
+static unsigned char days_in_mo[] =
 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
 static int irq_active;
@@ -89,18 +90,20 @@
 static int lostint;
 static int tt_exp;
 
-void gen_rtc_timer(unsigned long data);
+static void gen_rtc_timer(unsigned long data);
 
 static volatile int stask_active;              /* schedule_work */
 static volatile int ttask_active;              /* timer_task */
 static int stop_rtc_timers;                    /* don't requeue tasks */
 static spinlock_t gen_rtc_lock = SPIN_LOCK_UNLOCKED;
 
+static void gen_rtc_interrupt(unsigned long arg);
+
 /*
  * Routine to poll RTC seconds field for change as often as possible,
  * after first RTC_UIE use timer to reduce polling
  */
-void genrtc_troutine(void *data)
+static void genrtc_troutine(void *data)
 {
 	unsigned int tmp = get_rtc_ss();
 	
@@ -124,7 +127,7 @@
 		stask_active = 0;
 }
 
-void gen_rtc_timer(unsigned long data)
+static void gen_rtc_timer(unsigned long data)
 {
 	lostint = get_rtc_ss() - oldsecs ;
 	if (lostint<0) 
@@ -145,7 +148,7 @@
  * from some routine that periodically (eg 100HZ) monitors
  * whether RTC_SECS changed
  */
-void gen_rtc_interrupt(unsigned long arg)
+static void gen_rtc_interrupt(unsigned long arg)
 {
 	/*  We store the status in the low byte and the number of
 	 *	interrupts received since the last read in the remainder
@@ -175,7 +178,7 @@
 	unsigned long data;
 	ssize_t retval;
 
-        if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
+	if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
 		return -EINVAL;
 
 	if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data)
@@ -385,24 +388,24 @@
  */
 
 static struct file_operations gen_rtc_fops = {
-	.owner =	THIS_MODULE,
+	.owner		= THIS_MODULE,
 #ifdef CONFIG_GEN_RTC_X
-	.read =		gen_rtc_read,
-	.poll =		gen_rtc_poll,
+	.read		= gen_rtc_read,
+	.poll		= gen_rtc_poll,
 #endif
-	.ioctl =	gen_rtc_ioctl,
-	.open =		gen_rtc_open,
-	.release =	gen_rtc_release
+	.ioctl		= gen_rtc_ioctl,
+	.open		= gen_rtc_open,
+	.release	= gen_rtc_release,
 };
 
 static struct miscdevice rtc_gen_dev =
 {
-	RTC_MINOR,
-	"rtc",
-	&gen_rtc_fops
+	.minor		= RTC_MINOR,
+	.name		= "rtc",
+	.fops		= &gen_rtc_fops,
 };
 
-int __init rtc_generic_init(void)
+static int __init rtc_generic_init(void)
 {
 	int retval;
 
@@ -436,16 +439,18 @@
  *	Info exported via "/proc/rtc".
  */
 
-int gen_rtc_proc_output(char *buf)
+#ifdef CONFIG_PROC_FS
+
+static int gen_rtc_proc_output(char *buf)
 {
 	char *p;
 	struct rtc_time tm;
-	unsigned tmp;
+	unsigned int flags;
 	struct rtc_pll_info pll;
 
 	p = buf;
 
-	get_rtc_time(&tm);
+	flags = get_rtc_time(&tm);
 
 	p += sprintf(p,
 		     "rtc_time\t: %02d:%02d:%02d\n"
@@ -454,7 +459,7 @@
 		     tm.tm_hour, tm.tm_min, tm.tm_sec,
 		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900);
 
-	tm.tm_hour=0;tm.tm_min=0;tm.tm_sec=0;
+	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
 
 	p += sprintf(p, "alarm\t\t: ");
 	if (tm.tm_hour <= 24)
@@ -472,7 +477,6 @@
 	else
 		p += sprintf(p, "**\n");
 
-	tmp= RTC_24H ;
 	p += sprintf(p,
 		     "DST_enable\t: %s\n"
 		     "BCD\t\t: %s\n"
@@ -483,15 +487,15 @@
 		     "periodic_IRQ\t: %s\n"
 		     "periodic_freq\t: %ld\n"
 		     "batt_status\t: %s\n",
-		     (tmp & RTC_DST_EN) ? "yes" : "no",
-		     (tmp & RTC_DM_BINARY) ? "no" : "yes",
-		     (tmp & RTC_24H) ? "yes" : "no",
-		     (tmp & RTC_SQWE) ? "yes" : "no",
-		     (tmp & RTC_AIE) ? "yes" : "no",
+		     (flags & RTC_DST_EN) ? "yes" : "no",
+		     (flags & RTC_DM_BINARY) ? "no" : "yes",
+		     (flags & RTC_24H) ? "yes" : "no",
+		     (flags & RTC_SQWE) ? "yes" : "no",
+		     (flags & RTC_AIE) ? "yes" : "no",
 		     irq_active ? "yes" : "no",
-		     (tmp & RTC_PIE) ? "yes" : "no",
+		     (flags & RTC_PIE) ? "yes" : "no",
 		     0L /* freq */,
-		     "okay" );
+		     (flags & RTC_BATT_BAD) ? "bad" : "okay");
 	if (!get_rtc_pll(&pll))
 	    p += sprintf(p,
 			 "PLL adjustment\t: %d\n"
@@ -506,7 +510,7 @@
 			 pll.pll_posmult,
 			 pll.pll_negmult,
 			 pll.pll_clock);
-	return  p - buf;
+	return p - buf;
 }
 
 static int gen_rtc_read_proc(char *page, char **start, off_t off,
@@ -521,6 +525,9 @@
 	return len;
 }
 
+#endif /* CONFIG_PROC_FS */
+
 
 MODULE_AUTHOR("Richard Zidlicky");
 MODULE_LICENSE("GPL");
+
diff -urN linux-2.5.65-bk1/drivers/char/n_tty.c linux-2.5.65-bk2/drivers/char/n_tty.c
--- linux-2.5.65-bk1/drivers/char/n_tty.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/drivers/char/n_tty.c	Mon Mar 31 12:39:50 2003
@@ -1029,7 +1029,10 @@
 				break;
 			cs = tty->link->ctrl_status;
 			tty->link->ctrl_status = 0;
-			put_user(cs, b++);
+			if (put_user(cs, b++)) {
+				retval = -EFAULT;
+				break;
+			}
 			nr--;
 			break;
 		}
@@ -1068,7 +1071,10 @@
 
 		/* Deal with packet mode. */
 		if (tty->packet && b == buf) {
-			put_user(TIOCPKT_DATA, b++);
+			if (put_user(TIOCPKT_DATA, b++)) {
+				retval = -EFAULT;
+				break;
+			}
 			nr--;
 		}
 
@@ -1095,12 +1101,17 @@
 				spin_unlock_irqrestore(&tty->read_lock, flags);
 
 				if (!eol || (c != __DISABLED_CHAR)) {
-					put_user(c, b++);
+					if (put_user(c, b++)) {
+						retval = -EFAULT;
+						break;
+					}
 					nr--;
 				}
 				if (eol)
 					break;
 			}
+			if (retval)
+				break;
 		} else {
 			int uncopied;
 			uncopied = copy_from_read_buf(tty, &b, &nr);
@@ -1135,7 +1146,7 @@
 
 	current->state = TASK_RUNNING;
 	size = b - buf;
-	if (size) {
+	if (!retval && size) {
 		retval = size;
 		if (nr)
 	       		clear_bit(TTY_PUSH, &tty->flags);
diff -urN linux-2.5.65-bk1/drivers/char/raw.c linux-2.5.65-bk2/drivers/char/raw.c
--- linux-2.5.65-bk1/drivers/char/raw.c	Mon Mar 17 13:44:11 2003
+++ linux-2.5.65-bk2/drivers/char/raw.c	Mon Mar 31 12:39:50 2003
@@ -50,7 +50,7 @@
 		filp->f_op = &raw_ctl_fops;
 		return 0;
 	}
-	
+
 	down(&raw_mutex);
 
 	/*
@@ -70,10 +70,10 @@
 		} else {
 			err = set_blocksize(bdev, bdev_hardsect_size(bdev));
 			if (err == 0) {
-				raw_devices[minor].inuse++;
-				filp->f_dentry->d_inode->i_mapping =
-					bdev->bd_inode->i_mapping;
 				filp->f_flags |= O_DIRECT;
+				if (++raw_devices[minor].inuse == 1)
+					filp->f_dentry->d_inode->i_mapping =
+						bdev->bd_inode->i_mapping;
 			}
 		}
 	}
@@ -83,6 +83,10 @@
 	return err;
 }
 
+/*
+ * When the final fd which refers to this character-special node is closed, we
+ * make its ->mapping point back at its own i_data.
+ */
 static int raw_release(struct inode *inode, struct file *filp)
 {
 	const int minor= minor(inode->i_rdev);
@@ -90,13 +94,13 @@
 
 	down(&raw_mutex);
 	bdev = raw_devices[minor].binding;
-	raw_devices[minor].inuse--;
+	if (--raw_devices[minor].inuse == 0) {
+		/* Here  inode->i_mapping == bdev->bd_inode->i_mapping  */
+		inode->i_mapping = &inode->i_data;
+		inode->i_mapping->backing_dev_info = &default_backing_dev_info;
+	}
 	up(&raw_mutex);
 
-	/* Here  inode->i_mapping == bdev->bd_inode->i_mapping  */
-	inode->i_mapping = &inode->i_data;
-	inode->i_mapping->backing_dev_info = &default_backing_dev_info;
-	
 	bd_release(bdev);
 	blkdev_put(bdev, BDEV_RAW);
 	return 0;
@@ -118,27 +122,28 @@
  * Deal with ioctls against the raw-device control interface, to bind
  * and unbind other raw devices.
  */
-static int
-raw_ctl_ioctl(struct inode *inode, struct file *filp,
-		unsigned int command, unsigned long arg)
+static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
+			unsigned int command, unsigned long arg)
 {
 	struct raw_config_request rq;
 	struct raw_device_data *rawdev;
-	int err;
-	
+	int err = 0;
+
 	switch (command) {
 	case RAW_SETBIND:
 	case RAW_GETBIND:
 
 		/* First, find out which raw minor we want */
 
-		err = -EFAULT;
-		if (copy_from_user(&rq, (void *) arg, sizeof(rq)))
+		if (copy_from_user(&rq, (void *) arg, sizeof(rq))) {
+			err = -EFAULT;
 			goto out;
-		
-		err = -EINVAL;
-		if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS)
+		}
+
+		if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS) {
+			err = -EINVAL;
 			goto out;
+		}
 		rawdev = &raw_devices[rq.raw_minor];
 
 		if (command == RAW_SETBIND) {
@@ -148,9 +153,10 @@
 			 * This is like making block devices, so demand the
 			 * same capability
 			 */
-			err = -EPERM;
-			if (!capable(CAP_SYS_ADMIN))
+			if (!capable(CAP_SYS_ADMIN)) {
+				err = -EPERM;
 				goto out;
+			}
 
 			/*
 			 * For now, we don't need to check that the underlying
@@ -159,17 +165,18 @@
 			 * major/minor numbers make sense.
 			 */
 
-			err = -EINVAL;
 			dev = MKDEV(rq.block_major, rq.block_minor);
 			if ((rq.block_major == 0 && rq.block_minor != 0) ||
-			    MAJOR(dev) != rq.block_major ||
-			    MINOR(dev) != rq.block_minor)
+					MAJOR(dev) != rq.block_major ||
+					MINOR(dev) != rq.block_minor) {
+				err = -EINVAL;
 				goto out;
-			
+			}
+
 			down(&raw_mutex);
-			err = -EBUSY;
 			if (rawdev->inuse) {
 				up(&raw_mutex);
+				err = -EBUSY;
 				goto out;
 			}
 			if (rawdev->binding) {
@@ -181,7 +188,10 @@
 				rawdev->binding = NULL;
 			} else {
 				rawdev->binding = bdget(dev);
-				MOD_INC_USE_COUNT;
+				if (rawdev->binding == NULL)
+					err = -ENOMEM;
+				else
+					try_module_get(THIS_MODULE);
 			}
 			up(&raw_mutex);
 		} else {
@@ -196,13 +206,12 @@
 				rq.block_major = rq.block_minor = 0;
 			}
 			up(&raw_mutex);
-			err = -EFAULT;
-			if (copy_to_user((void *)arg, &rq, sizeof(rq)))
+			if (copy_to_user((void *)arg, &rq, sizeof(rq))) {
+				err = -EFAULT;
 				goto out;
+			}
 		}
-		err = 0;
 		break;
-		
 	default:
 		err = -EINVAL;
 		break;
diff -urN linux-2.5.65-bk1/drivers/char/serial167.c linux-2.5.65-bk2/drivers/char/serial167.c
--- linux-2.5.65-bk1/drivers/char/serial167.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/drivers/char/serial167.c	Mon Mar 31 12:39:50 2003
@@ -2836,7 +2836,7 @@
 };
 
 
-static void __init serial167_console_init(void)
+static int __init serial167_console_init(void)
 {
 	if (vme_brdtype == VME_TYPE_MVME166 ||
 			vme_brdtype == VME_TYPE_MVME167 ||
@@ -2844,6 +2844,7 @@
 		mvme167_serial_console_setup(0);
 		register_console(&sercons);
 	}
+	return 0;
 }
 console_initcall(serial167_console_init);
 
diff -urN linux-2.5.65-bk1/drivers/char/serial_tx3912.c linux-2.5.65-bk2/drivers/char/serial_tx3912.c
--- linux-2.5.65-bk1/drivers/char/serial_tx3912.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/drivers/char/serial_tx3912.c	Mon Mar 31 12:39:50 2003
@@ -1054,9 +1054,10 @@
 	.index    = -1
 };
 
-static void __init tx3912_console_init(void)
+static int __init tx3912_console_init(void)
 {
 	register_console(&sercons);
+	return 0;
 }
 console_initcall(tx3912_console_init);
 
diff -urN linux-2.5.65-bk1/drivers/char/sh-sci.c linux-2.5.65-bk2/drivers/char/sh-sci.c
--- linux-2.5.65-bk1/drivers/char/sh-sci.c	Mon Mar 17 13:44:46 2003
+++ linux-2.5.65-bk2/drivers/char/sh-sci.c	Mon Mar 31 12:39:50 2003
@@ -1275,7 +1275,7 @@
 extern void sh_console_unregister (void);
 #endif
 
-static void __init sci_console_init(void)
+static int __init sci_console_init(void)
 {
 	register_console(&sercons);
 #ifdef CONFIG_SH_EARLY_PRINTK
@@ -1284,6 +1284,7 @@
 	 */
 	sh_console_unregister();
 #endif
+	return 0;
 }
 console_initcall(sci_console_init);
 
diff -urN linux-2.5.65-bk1/drivers/char/vme_scc.c linux-2.5.65-bk2/drivers/char/vme_scc.c
--- linux-2.5.65-bk1/drivers/char/vme_scc.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/drivers/char/vme_scc.c	Mon Mar 31 12:39:50 2003
@@ -1091,7 +1091,7 @@
 };
 
 
-static void __init vme_scc_console_init(void)
+static int __init vme_scc_console_init(void)
 {
 	if (vme_brdtype == VME_TYPE_MVME147 ||
 			vme_brdtype == VME_TYPE_MVME162 ||
@@ -1099,5 +1099,6 @@
 			vme_brdtype == VME_TYPE_BVME4000 ||
 			vme_brdtype == VME_TYPE_BVME6000)
 		register_console(&sercons);
+	return 0;
 }
 console_initcall(vme_scc_console_init);
diff -urN linux-2.5.65-bk1/drivers/i2c/busses/Kconfig linux-2.5.65-bk2/drivers/i2c/busses/Kconfig
--- linux-2.5.65-bk1/drivers/i2c/busses/Kconfig	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/drivers/i2c/busses/Kconfig	Mon Mar 31 12:39:50 2003
@@ -76,6 +76,24 @@
 	  in the lm_sensors package, which you can download at 
 	  http://www.lm-sensors.nu
 
+config I2C_ISA
+	tristate "  ISA Bus support"
+	depends on I2C && I2C_PROC && ISA && EXPERIMENTAL
+	help
+	  If you say yes to this option, support will be included for i2c
+	  interfaces that are on the ISA bus.
+
+	  This can also be built as a module which can be inserted and removed 
+	  while the kernel is running.  If you want to compile it as a module,
+	  say M here and read <file:Documentation/modules.txt>.
+
+	  The module will be called i2c-isa.
+
+	  You will also need the latest user-space utilties: you can find them
+	  in the lm_sensors package, which you can download at 
+	  http://www.lm-sensors.nu
+
+
 config I2C_PIIX4
 	tristate "  Intel PIIX4"
 	depends on I2C && I2C_PROC && PCI && EXPERIMENTAL
diff -urN linux-2.5.65-bk1/drivers/i2c/busses/Makefile linux-2.5.65-bk2/drivers/i2c/busses/Makefile
--- linux-2.5.65-bk1/drivers/i2c/busses/Makefile	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/drivers/i2c/busses/Makefile	Mon Mar 31 12:39:50 2003
@@ -6,4 +6,5 @@
 obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
 obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
 obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
+obj-$(CONFIG_I2C_ISA)		+= i2c-isa.o
 obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
diff -urN linux-2.5.65-bk1/drivers/i2c/busses/i2c-ali15x3.c linux-2.5.65-bk2/drivers/i2c/busses/i2c-ali15x3.c
--- linux-2.5.65-bk1/drivers/i2c/busses/i2c-ali15x3.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/drivers/i2c/busses/i2c-ali15x3.c	Mon Mar 31 12:39:50 2003
@@ -60,6 +60,8 @@
 
 /* Note: we assume there can only be one ALI15X3, with one SMBus interface */
 
+/* #define DEBUG 1 */
+
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
@@ -71,46 +73,46 @@
 #include <asm/io.h>
 
 /* ALI15X3 SMBus address offsets */
-#define SMBHSTSTS (0 + ali15x3_smba)
-#define SMBHSTCNT (1 + ali15x3_smba)
-#define SMBHSTSTART (2 + ali15x3_smba)
-#define SMBHSTCMD (7 + ali15x3_smba)
-#define SMBHSTADD (3 + ali15x3_smba)
-#define SMBHSTDAT0 (4 + ali15x3_smba)
-#define SMBHSTDAT1 (5 + ali15x3_smba)
-#define SMBBLKDAT (6 + ali15x3_smba)
+#define SMBHSTSTS	(0 + ali15x3_smba)
+#define SMBHSTCNT	(1 + ali15x3_smba)
+#define SMBHSTSTART	(2 + ali15x3_smba)
+#define SMBHSTCMD	(7 + ali15x3_smba)
+#define SMBHSTADD	(3 + ali15x3_smba)
+#define SMBHSTDAT0	(4 + ali15x3_smba)
+#define SMBHSTDAT1	(5 + ali15x3_smba)
+#define SMBBLKDAT	(6 + ali15x3_smba)
 
 /* PCI Address Constants */
-#define SMBCOM    0x004
-#define SMBBA     0x014
-#define SMBATPC   0x05B		/* used to unlock xxxBA registers */
-#define SMBHSTCFG 0x0E0
-#define SMBSLVC   0x0E1
-#define SMBCLK    0x0E2
-#define SMBREV    0x008
+#define SMBCOM		0x004
+#define SMBBA		0x014
+#define SMBATPC		0x05B	/* used to unlock xxxBA registers */
+#define SMBHSTCFG	0x0E0
+#define SMBSLVC		0x0E1
+#define SMBCLK		0x0E2
+#define SMBREV		0x008
 
 /* Other settings */
-#define MAX_TIMEOUT 200		/* times 1/100 sec */
-#define ALI15X3_SMB_IOSIZE 32
+#define MAX_TIMEOUT		200	/* times 1/100 sec */
+#define ALI15X3_SMB_IOSIZE	32
 
 /* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
    We don't use these here. If the bases aren't set to some value we
    tell user to upgrade BIOS and we fail.
 */
-#define ALI15X3_SMB_DEFAULTBASE 0xE800
+#define ALI15X3_SMB_DEFAULTBASE	0xE800
 
 /* ALI15X3 address lock bits */
-#define ALI15X3_LOCK	0x06
+#define ALI15X3_LOCK		0x06
 
 /* ALI15X3 command constants */
-#define ALI15X3_ABORT      0x02
-#define ALI15X3_T_OUT      0x04
-#define ALI15X3_QUICK      0x00
-#define ALI15X3_BYTE       0x10
-#define ALI15X3_BYTE_DATA  0x20
-#define ALI15X3_WORD_DATA  0x30
-#define ALI15X3_BLOCK_DATA 0x40
-#define ALI15X3_BLOCK_CLR  0x80
+#define ALI15X3_ABORT		0x02
+#define ALI15X3_T_OUT		0x04
+#define ALI15X3_QUICK		0x00
+#define ALI15X3_BYTE		0x10
+#define ALI15X3_BYTE_DATA	0x20
+#define ALI15X3_WORD_DATA	0x30
+#define ALI15X3_BLOCK_DATA	0x40
+#define ALI15X3_BLOCK_CLR	0x80
 
 /* ALI15X3 status register bits */
 #define ALI15X3_STS_IDLE	0x04
@@ -129,55 +131,52 @@
 MODULE_PARM_DESC(force_addr,
 		 "Initialize the base address of the i2c controller");
 
-
-static void ali15x3_do_pause(unsigned int amount);
-static int ali15x3_transaction(void);
-
 static unsigned short ali15x3_smba = 0;
 
-int ali15x3_setup(struct pci_dev *ALI15X3_dev)
+static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
 {
 	u16 a;
 	unsigned char temp;
 
-/* Check the following things:
-	- SMB I/O address is initialized
-	- Device is enabled
-	- We can use the addresses
-*/
-
-/* Unlock the register.
-   The data sheet says that the address registers are read-only
-   if the lock bits are 1, but in fact the address registers
-   are zero unless you clear the lock bits.
-*/
+	/* Check the following things:
+		- SMB I/O address is initialized
+		- Device is enabled
+		- We can use the addresses
+	*/
+
+	/* Unlock the register.
+	   The data sheet says that the address registers are read-only
+	   if the lock bits are 1, but in fact the address registers
+	   are zero unless you clear the lock bits.
+	*/
 	pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
 	if (temp & ALI15X3_LOCK) {
 		temp &= ~ALI15X3_LOCK;
 		pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
 	}
 
-/* Determine the address of the SMBus area */
+	/* Determine the address of the SMBus area */
 	pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
 	ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
 	if (ali15x3_smba == 0 && force_addr == 0) {
-		printk
-		    ("i2c-ali15x3.o: ALI15X3_smb region uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+		dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized "
+			"- upgrade BIOS or use force_addr=0xaddr\n");
 		return -ENODEV;
 	}
 
 	if(force_addr)
 		ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
 
-	if (check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE)) {
-		printk
-		    ("i2c-ali15x3.o: ALI15X3_smb region 0x%x already in use!\n",
-		     ali15x3_smba);
+	if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb")) {
+		dev_err(&ALI15X3_dev->dev,
+			"ALI15X3_smb region 0x%x already in use!\n",
+			ali15x3_smba);
 		return -ENODEV;
 	}
 
 	if(force_addr) {
-		printk("i2c-ali15x3.o: forcing ISA address 0x%04X\n", ali15x3_smba);
+		dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n",
+			ali15x3_smba);
 		if (PCIBIOS_SUCCESSFUL !=
 		    pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba))
 			return -ENODEV;
@@ -186,68 +185,60 @@
 			return -ENODEV;
 		if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
 			/* make sure it works */
-			printk("i2c-ali15x3.o: force address failed - not supported?\n");
+			dev_err(&ALI15X3_dev->dev,
+				"force address failed - not supported?\n");
 			return -ENODEV;
 		}
 	}
-/* check if whole device is enabled */
+	/* check if whole device is enabled */
 	pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
 	if ((temp & 1) == 0) {
-		printk("i2c-ali15x3: enabling SMBus device\n");
+		dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n");
 		pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
 	}
 
-/* Is SMB Host controller enabled? */
+	/* Is SMB Host controller enabled? */
 	pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
 	if ((temp & 1) == 0) {
-		printk("i2c-ali15x3: enabling SMBus controller\n");
+		dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n");
 		pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
 	}
 
-/* set SMB clock to 74KHz as recommended in data sheet */
+	/* set SMB clock to 74KHz as recommended in data sheet */
 	pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
 
-	/* Everything is happy, let's grab the memory and set things up. */
-	request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb");
-
-#ifdef DEBUG
-/*
-  The interrupt routing for SMB is set up in register 0x77 in the
-  1533 ISA Bridge device, NOT in the 7101 device.
-  Don't bother with finding the 1533 device and reading the register.
-  if ((....... & 0x0F) == 1)
-     printk("i2c-ali15x3.o: ALI15X3 using Interrupt 9 for SMBus.\n");
-*/
+	/*
+	  The interrupt routing for SMB is set up in register 0x77 in the
+	  1533 ISA Bridge device, NOT in the 7101 device.
+	  Don't bother with finding the 1533 device and reading the register.
+	if ((....... & 0x0F) == 1)
+		dev_dbg(&ALI15X3_dev->dev, "ALI15X3 using Interrupt 9 for SMBus.\n");
+	*/
 	pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
-	printk("i2c-ali15x3.o: SMBREV = 0x%X\n", temp);
-	printk("i2c-ali15x3.o: ALI15X3_smba = 0x%X\n", ali15x3_smba);
-#endif				/* DEBUG */
+	dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp);
+	dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
 
 	return 0;
 }
 
-
 /* Internally used pause function */
-void ali15x3_do_pause(unsigned int amount)
+static void ali15x3_do_pause(unsigned int amount)
 {
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(amount);
 }
 
 /* Another internally used function */
-int ali15x3_transaction(void)
+static int ali15x3_transaction(struct i2c_adapter *adap)
 {
 	int temp;
 	int result = 0;
 	int timeout = 0;
 
-#ifdef DEBUG
-	printk
-	    ("i2c-ali15x3.o: Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
-	     "DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
-	     inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-	     inb_p(SMBHSTDAT1));
-#endif
+	dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
 
 	/* get status */
 	temp = inb_p(SMBHSTSTS);
@@ -255,43 +246,32 @@
 	/* Make sure the SMBus host is ready to start transmitting */
 	/* Check the busy bit first */
 	if (temp & ALI15X3_STS_BUSY) {
-/*
-   If the host controller is still busy, it may have timed out in the previous transaction,
-   resulting in a "SMBus Timeout" printk.
-   I've tried the following to reset a stuck busy bit.
-	1. Reset the controller with an ABORT command.
-	   (this doesn't seem to clear the controller if an external device is hung)
-	2. Reset the controller and the other SMBus devices with a T_OUT command.
-	   (this clears the host busy bit if an external device is hung,
-	   but it comes back upon a new access to a device)
-	3. Disable and reenable the controller in SMBHSTCFG
-   Worst case, nothing seems to work except power reset.
-*/
-/* Abort - reset the host controller */
-/*
-#ifdef DEBUG
-    printk("i2c-ali15x3.o: Resetting host controller to clear busy condition\n",temp);
-#endif
-    outb_p(ALI15X3_ABORT, SMBHSTCNT);
-    temp = inb_p(SMBHSTSTS);
-    if (temp & ALI15X3_STS_BUSY) {
-*/
-
-/*
-   Try resetting entire SMB bus, including other devices -
-   This may not work either - it clears the BUSY bit but
-   then the BUSY bit may come back on when you try and use the chip again.
-   If that's the case you are stuck.
-*/
-		printk
-		    ("i2c-ali15x3.o: Resetting entire SMB Bus to clear busy condition (%02x)\n",
-		     temp);
+	/*
+	   If the host controller is still busy, it may have timed out in the
+	   previous transaction, resulting in a "SMBus Timeout" Dev.
+	   I've tried the following to reset a stuck busy bit.
+		1. Reset the controller with an ABORT command.
+		   (this doesn't seem to clear the controller if an external
+		   device is hung)
+		2. Reset the controller and the other SMBus devices with a
+		   T_OUT command.  (this clears the host busy bit if an
+		   external device is hung, but it comes back upon a new access
+		   to a device)
+		3. Disable and reenable the controller in SMBHSTCFG
+	   Worst case, nothing seems to work except power reset.
+	*/
+	/* Abort - reset the host controller */
+	/*
+	   Try resetting entire SMB bus, including other devices -
+	   This may not work either - it clears the BUSY bit but
+	   then the BUSY bit may come back on when you try and use the chip again.
+	   If that's the case you are stuck.
+	*/
+		dev_info(&adap->dev, "Resetting entire SMB Bus to "
+			"clear busy condition (%02x)\n", temp);
 		outb_p(ALI15X3_T_OUT, SMBHSTCNT);
 		temp = inb_p(SMBHSTSTS);
 	}
-/*
-  }
-*/
 
 	/* now check the error bits and the busy bit */
 	if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
@@ -302,9 +282,9 @@
 			/* this is probably going to be correctable only by a power reset
 			   as one of the bits now appears to be stuck */
 			/* This may be a bus or device with electrical problems. */
-			printk
-			    ("i2c-ali15x3.o: SMBus reset failed! (0x%02x) - controller or device on bus is probably hung\n",
-			     temp);
+			dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
+				"controller or device on bus is probably hung\n",
+				temp);
 			return -1;
 		}
 	} else {
@@ -328,48 +308,41 @@
 	/* If the SMBus is still busy, we give up */
 	if (timeout >= MAX_TIMEOUT) {
 		result = -1;
-		printk("i2c-ali15x3.o: SMBus Timeout!\n");
+		dev_err(&adap->dev, "SMBus Timeout!\n");
 	}
 
 	if (temp & ALI15X3_STS_TERM) {
 		result = -1;
-#ifdef DEBUG
-		printk("i2c-ali15x3.o: Error: Failed bus transaction\n");
-#endif
+		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
 	}
 
-/*
-  Unfortunately the ALI SMB controller maps "no response" and "bus collision"
-  into a single bit. No reponse is the usual case so don't
-  do a printk.
-  This means that bus collisions go unreported.
-*/
+	/*
+	  Unfortunately the ALI SMB controller maps "no response" and "bus
+	  collision" into a single bit. No reponse is the usual case so don't
+	  do a printk.
+	  This means that bus collisions go unreported.
+	*/
 	if (temp & ALI15X3_STS_COLL) {
 		result = -1;
-#ifdef DEBUG
-		printk
-		    ("i2c-ali15x3.o: Error: no response or bus collision ADD=%02x\n",
-		     inb_p(SMBHSTADD));
-#endif
+		dev_dbg(&adap->dev,
+			"Error: no response or bus collision ADD=%02x\n",
+			inb_p(SMBHSTADD));
 	}
 
-/* haven't ever seen this */
+	/* haven't ever seen this */
 	if (temp & ALI15X3_STS_DEV) {
 		result = -1;
-		printk("i2c-ali15x3.o: Error: device error\n");
+		dev_err(&adap->dev, "Error: device error\n");
 	}
-#ifdef DEBUG
-	printk
-	    ("i2c-ali15x3.o: Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, "
-	     "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
-	     inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-	     inb_p(SMBHSTDAT1));
-#endif
+	dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
 	return result;
 }
 
 /* Return -1 on error. */
-s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
+static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
 		   unsigned short flags, char read_write, u8 command,
 		   int size, union i2c_smbus_data * data)
 {
@@ -377,9 +350,9 @@
 	int temp;
 	int timeout;
 
-/* clear all the bits (clear-on-write) */
+	/* clear all the bits (clear-on-write) */
 	outb_p(0xFF, SMBHSTSTS);
-/* make sure SMBus is idle */
+	/* make sure SMBus is idle */
 	temp = inb_p(SMBHSTSTS);
 	for (timeout = 0;
 	     (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
@@ -388,14 +361,12 @@
 		temp = inb_p(SMBHSTSTS);
 	}
 	if (timeout >= MAX_TIMEOUT) {
-		printk("i2c-ali15x3.o: Idle wait Timeout! STS=0x%02x\n",
-		       temp);
+		dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
 	}
 
 	switch (size) {
 	case I2C_SMBUS_PROC_CALL:
-		printk
-		    ("i2c-ali15x3.o: I2C_SMBUS_PROC_CALL not supported!\n");
+		dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
 		return -1;
 	case I2C_SMBUS_QUICK:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
@@ -442,7 +413,8 @@
 				data->block[0] = len;
 			}
 			outb_p(len, SMBHSTDAT0);
-			outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);	/* Reset SMBBLKDAT */
+			/* Reset SMBBLKDAT */
+			outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
 			for (i = 1; i <= len; i++)
 				outb_p(data->block[i], SMBBLKDAT);
 		}
@@ -452,7 +424,7 @@
 
 	outb_p(size, SMBHSTCNT);	/* output command */
 
-	if (ali15x3_transaction())	/* Error in transaction */
+	if (ali15x3_transaction(adap))	/* Error in transaction */
 		return -1;
 
 	if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
@@ -474,22 +446,19 @@
 		if (len > 32)
 			len = 32;
 		data->block[0] = len;
-		outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);	/* Reset SMBBLKDAT */
+		/* Reset SMBBLKDAT */
+		outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
 		for (i = 1; i <= data->block[0]; i++) {
 			data->block[i] = inb_p(SMBBLKDAT);
-#ifdef DEBUG
-			printk
-			    ("i2c-ali15x3.o: Blk: len=%d, i=%d, data=%02x\n",
-			     len, i, data->block[i]);
-#endif	/* DEBUG */
+			dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+				len, i, data->block[i]);
 		}
 		break;
 	}
 	return 0;
 }
 
-
-u32 ali15x3_func(struct i2c_adapter *adapter)
+static u32 ali15x3_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
 	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
@@ -510,8 +479,6 @@
 	.algo		= &smbus_algorithm,
 };
 
-
-
 static struct pci_device_id ali15x3_ids[] __devinitdata = {
 	{
 	.vendor =	PCI_VENDOR_ID_AL,
@@ -525,9 +492,8 @@
 static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	if (ali15x3_setup(dev)) {
-		printk
-		    ("i2c-ali15x3.o: ALI15X3 not detected, module not inserted.\n");
-
+		dev_err(&dev->dev,
+			"ALI15X3 not detected, module not inserted.\n");
 		return -ENODEV;
 	}
 
@@ -557,17 +523,15 @@
 	return pci_module_init(&ali15x3_driver);
 }
 
-
 static void __exit i2c_ali15x3_exit(void)
 {
 	pci_unregister_driver(&ali15x3_driver);
 	release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
 }
 
-
-
-MODULE_AUTHOR
-    ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+		"Philip Edelbrock <phil@netroedge.com>, "
+		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
 MODULE_DESCRIPTION("ALI15X3 SMBus driver");
 MODULE_LICENSE("GPL");
 
diff -urN linux-2.5.65-bk1/drivers/i2c/busses/i2c-amd756.c linux-2.5.65-bk2/drivers/i2c/busses/i2c-amd756.c
--- linux-2.5.65-bk1/drivers/i2c/busses/i2c-amd756.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/drivers/i2c/busses/i2c-amd756.c	Mon Mar 31 12:39:50 2003
@@ -35,6 +35,8 @@
    Note: we assume there can only be one device, with one SMBus interface.
 */
 
+/* #define DEBUG 1 */
+
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -46,44 +48,42 @@
 #include <linux/init.h>
 #include <asm/io.h>
 
-#define DRV_NAME	"i2c-amd756"
-
 /* AMD756 SMBus address offsets */
-#define SMB_ADDR_OFFSET        0xE0
-#define SMB_IOSIZE             16
-#define SMB_GLOBAL_STATUS      (0x0 + amd756_ioport)
-#define SMB_GLOBAL_ENABLE      (0x2 + amd756_ioport)
-#define SMB_HOST_ADDRESS       (0x4 + amd756_ioport)
-#define SMB_HOST_DATA          (0x6 + amd756_ioport)
-#define SMB_HOST_COMMAND       (0x8 + amd756_ioport)
-#define SMB_HOST_BLOCK_DATA    (0x9 + amd756_ioport)
-#define SMB_HAS_DATA           (0xA + amd756_ioport)
-#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport)
-#define SMB_HAS_HOST_ADDRESS   (0xE + amd756_ioport)
-#define SMB_SNOOP_ADDRESS      (0xF + amd756_ioport)
+#define SMB_ADDR_OFFSET		0xE0
+#define SMB_IOSIZE		16
+#define SMB_GLOBAL_STATUS	(0x0 + amd756_ioport)
+#define SMB_GLOBAL_ENABLE	(0x2 + amd756_ioport)
+#define SMB_HOST_ADDRESS	(0x4 + amd756_ioport)
+#define SMB_HOST_DATA		(0x6 + amd756_ioport)
+#define SMB_HOST_COMMAND	(0x8 + amd756_ioport)
+#define SMB_HOST_BLOCK_DATA	(0x9 + amd756_ioport)
+#define SMB_HAS_DATA		(0xA + amd756_ioport)
+#define SMB_HAS_DEVICE_ADDRESS	(0xC + amd756_ioport)
+#define SMB_HAS_HOST_ADDRESS	(0xE + amd756_ioport)
+#define SMB_SNOOP_ADDRESS	(0xF + amd756_ioport)
 
 /* PCI Address Constants */
 
 /* address of I/O space */
-#define SMBBA     0x058		/* mh */
-#define SMBBANFORCE     0x014
+#define SMBBA		0x058		/* mh */
+#define SMBBANFORCE	0x014
 
 /* general configuration */
-#define SMBGCFG   0x041		/* mh */
+#define SMBGCFG		0x041		/* mh */
 
 /* silicon revision code */
-#define SMBREV    0x008
+#define SMBREV		0x008
 
 /* Other settings */
-#define MAX_TIMEOUT 500
+#define MAX_TIMEOUT	500
 
 /* AMD756 constants */
-#define AMD756_QUICK        0x00
-#define AMD756_BYTE         0x01
-#define AMD756_BYTE_DATA    0x02
-#define AMD756_WORD_DATA    0x03
-#define AMD756_PROCESS_CALL 0x04
-#define AMD756_BLOCK_DATA   0x05
+#define AMD756_QUICK		0x00
+#define AMD756_BYTE		0x01
+#define AMD756_BYTE_DATA	0x02
+#define AMD756_WORD_DATA	0x03
+#define AMD756_PROCESS_CALL	0x04
+#define AMD756_BLOCK_DATA	0x05
 
 
 static unsigned short amd756_ioport = 0;
@@ -101,36 +101,36 @@
 	schedule_timeout(amount);
 }
 
-#define GS_ABRT_STS (1 << 0)
-#define GS_COL_STS (1 << 1)
-#define GS_PRERR_STS (1 << 2)
-#define GS_HST_STS (1 << 3)
-#define GS_HCYC_STS (1 << 4)
-#define GS_TO_STS (1 << 5)
-#define GS_SMB_STS (1 << 11)
-
-#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
-  GS_HCYC_STS | GS_TO_STS )
-
-#define GE_CYC_TYPE_MASK (7)
-#define GE_HOST_STC (1 << 3)
-#define GE_ABORT (1 << 5)
+#define GS_ABRT_STS	(1 << 0)
+#define GS_COL_STS	(1 << 1)
+#define GS_PRERR_STS	(1 << 2)
+#define GS_HST_STS	(1 << 3)
+#define GS_HCYC_STS	(1 << 4)
+#define GS_TO_STS	(1 << 5)
+#define GS_SMB_STS	(1 << 11)
+
+#define GS_CLEAR_STS	(GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
+			 GS_HCYC_STS | GS_TO_STS )
+
+#define GE_CYC_TYPE_MASK	(7)
+#define GE_HOST_STC		(1 << 3)
+#define GE_ABORT		(1 << 5)
 
 
-static int amd756_transaction(void)
+static int amd756_transaction(struct i2c_adapter *adap)
 {
 	int temp;
 	int result = 0;
 	int timeout = 0;
 
-	pr_debug(DRV_NAME
-	       ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
-	       inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
-	       inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+	dev_dbg(&adap->dev, ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
+		"DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
+		inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
+		inb_p(SMB_HOST_DATA));
 
 	/* Make sure the SMBus host is ready to start transmitting */
 	if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
-		pr_debug(DRV_NAME ": SMBus busy (%04x). Waiting... \n", temp);
+		dev_dbg(&adap->dev, ": SMBus busy (%04x). Waiting... \n", temp);
 		do {
 			amd756_do_pause(1);
 			temp = inw_p(SMB_GLOBAL_STATUS);
@@ -138,7 +138,7 @@
 		         (timeout++ < MAX_TIMEOUT));
 		/* If the SMBus is still busy, we give up */
 		if (timeout >= MAX_TIMEOUT) {
-			pr_debug(DRV_NAME ": Busy wait timeout (%04x)\n", temp);
+			dev_dbg(&adap->dev, ": Busy wait timeout (%04x)\n", temp);
 			goto abort;
 		}
 		timeout = 0;
@@ -155,46 +155,46 @@
 
 	/* If the SMBus is still busy, we give up */
 	if (timeout >= MAX_TIMEOUT) {
-		pr_debug(DRV_NAME ": Completion timeout!\n");
+		dev_dbg(&adap->dev, ": Completion timeout!\n");
 		goto abort;
 	}
 
 	if (temp & GS_PRERR_STS) {
 		result = -1;
-		pr_debug(DRV_NAME ": SMBus Protocol error (no response)!\n");
+		dev_dbg(&adap->dev, ": SMBus Protocol error (no response)!\n");
 	}
 
 	if (temp & GS_COL_STS) {
 		result = -1;
-		printk(KERN_WARNING DRV_NAME " SMBus collision!\n");
+		dev_warn(&adap->dev, " SMBus collision!\n");
 	}
 
 	if (temp & GS_TO_STS) {
 		result = -1;
-		pr_debug(DRV_NAME ": SMBus protocol timeout!\n");
+		dev_dbg(&adap->dev, ": SMBus protocol timeout!\n");
 	}
 
 	if (temp & GS_HCYC_STS)
-		pr_debug(DRV_NAME " SMBus protocol success!\n");
+		dev_dbg(&adap->dev, " SMBus protocol success!\n");
 
 	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
 
 #ifdef DEBUG
 	if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
-		pr_debug(DRV_NAME
-		         ": Failed reset at end of transaction (%04x)\n", temp);
+		dev_dbg(&adap->dev,
+			": Failed reset at end of transaction (%04x)\n", temp);
 	}
-
-	pr_debug(DRV_NAME
-		 ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
-		 inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
-		 inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
 #endif
 
+	dev_dbg(&adap->dev,
+		": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
+		inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
+		inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+
 	return result;
 
  abort:
-	printk(KERN_WARNING DRV_NAME ": Sending abort.\n");
+	dev_warn(&adap->dev, ": Sending abort.\n");
 	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
 	amd756_do_pause(100);
 	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
@@ -211,7 +211,7 @@
 	/** TODO: Should I supporte the 10-bit transfers? */
 	switch (size) {
 	case I2C_SMBUS_PROC_CALL:
-		pr_debug(DRV_NAME ": I2C_SMBUS_PROC_CALL not supported!\n");
+		dev_dbg(&adap->dev, ": I2C_SMBUS_PROC_CALL not supported!\n");
 		/* TODO: Well... It is supported, I'm just not sure what to do here... */
 		return -1;
 	case I2C_SMBUS_QUICK:
@@ -266,7 +266,7 @@
 	/* How about enabling interrupts... */
 	outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
 
-	if (amd756_transaction())	/* Error in transaction */
+	if (amd756_transaction(adap))	/* Error in transaction */
 		return -1;
 
 	if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
@@ -334,7 +334,7 @@
 	u8 temp;
 	
 	if (amd756_ioport) {
-		printk(KERN_ERR DRV_NAME ": Only one device supported. "
+		dev_err(&pdev->dev, ": Only one device supported. "
 		       "(you have a strange motherboard, btw..)\n");
 		return -ENODEV;
 	}
@@ -351,8 +351,8 @@
 
 		pci_read_config_byte(pdev, SMBGCFG, &temp);
 		if ((temp & 128) == 0) {
-			printk(KERN_ERR DRV_NAME
-			       ": Error: SMBus controller I/O not enabled!\n");
+			dev_err(&pdev->dev,
+				": Error: SMBus controller I/O not enabled!\n");
 			return -ENODEV;
 		}
 
@@ -364,16 +364,14 @@
 	}
 
 	if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) {
-		printk(KERN_ERR DRV_NAME
-		       ": SMB region 0x%x already in use!\n", amd756_ioport);
+		dev_err(&pdev->dev, ": SMB region 0x%x already in use!\n",
+			amd756_ioport);
 		return -ENODEV;
 	}
 
-#ifdef DEBUG
 	pci_read_config_byte(pdev, SMBREV, &temp);
-	printk(KERN_DEBUG DRV_NAME ": SMBREV = 0x%X\n", temp);
-	printk(KERN_DEBUG DRV_NAME ": AMD756_smba = 0x%X\n", amd756_ioport);
-#endif
+	dev_dbg(&pdev->dev, ": SMBREV = 0x%X\n", temp);
+	dev_dbg(&pdev->dev, ": AMD756_smba = 0x%X\n", amd756_ioport);
 
 	/* set up the driverfs linkage to our parent device */
 	amd756_adapter.dev.parent = &pdev->dev;
@@ -383,8 +381,8 @@
 
 	error = i2c_add_adapter(&amd756_adapter);
 	if (error) {
-		printk(KERN_ERR DRV_NAME
-		       ": Adapter registration failed, module not inserted.\n");
+		dev_err(&pdev->dev,
+			": Adapter registration failed, module not inserted.\n");
 		goto out_err;
 	}
 
diff -urN linux-2.5.65-bk1/drivers/i2c/busses/i2c-amd8111.c linux-2.5.65-bk2/drivers/i2c/busses/i2c-amd8111.c
--- linux-2.5.65-bk1/drivers/i2c/busses/i2c-amd8111.c	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/drivers/i2c/busses/i2c-amd8111.c	Mon Mar 31 12:39:50 2003
@@ -74,7 +74,7 @@
 		udelay(1);
 
 	if (!timeout) {
-		printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n");
+		dev_warn(&smbus->dev->dev, "Timeout while waiting for IBF to clear\n");
 		return -1;
 	}
 
@@ -89,7 +89,7 @@
 		udelay(1);
 
 	if (!timeout) {
-		printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for OBF to set\n");
+		dev_warn(&smbus->dev->dev, "Timeout while waiting for OBF to set\n");
 		return -1;
 	}
 
@@ -256,11 +256,11 @@
 		case I2C_SMBUS_BLOCK_DATA_PEC:
 		case I2C_SMBUS_PROC_CALL_PEC:
 		case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
-			printk(KERN_WARNING "i2c-amd8111.c: Unexpected software PEC transaction %d\n.", size);
+			dev_warn(&adap->dev, "Unexpected software PEC transaction %d\n.", size);
 			return -1;
 
 		default:
-			printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size);
+			dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
 			return -1;
 	}
 
@@ -392,7 +392,7 @@
 }
 
 static struct pci_driver amd8111_driver = {
-	.name		= "amd8111 smbus",
+	.name		= "amd8111 smbus 2",
 	.id_table	= amd8111_ids,
 	.probe		= amd8111_probe,
 	.remove		= __devexit_p(amd8111_remove),
diff -urN linux-2.5.65-bk1/drivers/i2c/busses/i2c-i801.c linux-2.5.65-bk2/drivers/i2c/busses/i2c-i801.c
--- linux-2.5.65-bk1/drivers/i2c/busses/i2c-i801.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/drivers/i2c/busses/i2c-i801.c	Mon Mar 31 12:39:50 2003
@@ -49,65 +49,48 @@
 #include <linux/i2c.h>
 #include <asm/io.h>
 
-MODULE_LICENSE("GPL");
-
 #ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
 #define HAVE_PEC
 #endif
 
-#ifndef PCI_DEVICE_ID_INTEL_82801CA_SMBUS
-#define PCI_DEVICE_ID_INTEL_82801CA_SMBUS	0x2483
-#endif
-
-#ifndef PCI_DEVICE_ID_INTEL_82801DB_SMBUS
-#define PCI_DEVICE_ID_INTEL_82801DB_SMBUS	0x24C3
-#endif
-
-static int supported[] = {PCI_DEVICE_ID_INTEL_82801AA_3,
-                          PCI_DEVICE_ID_INTEL_82801AB_3,
-                          PCI_DEVICE_ID_INTEL_82801BA_2,
-			  PCI_DEVICE_ID_INTEL_82801CA_SMBUS,
-			  PCI_DEVICE_ID_INTEL_82801DB_SMBUS,
-                          0 };
-
 /* I801 SMBus address offsets */
-#define SMBHSTSTS (0 + i801_smba)
-#define SMBHSTCNT (2 + i801_smba)
-#define SMBHSTCMD (3 + i801_smba)
-#define SMBHSTADD (4 + i801_smba)
-#define SMBHSTDAT0 (5 + i801_smba)
-#define SMBHSTDAT1 (6 + i801_smba)
-#define SMBBLKDAT (7 + i801_smba)
-#define SMBPEC    (8 + i801_smba)	/* ICH4 only */
-#define SMBAUXSTS (12 + i801_smba)	/* ICH4 only */
-#define SMBAUXCTL (13 + i801_smba)	/* ICH4 only */
+#define SMBHSTSTS	(0 + i801_smba)
+#define SMBHSTCNT	(2 + i801_smba)
+#define SMBHSTCMD	(3 + i801_smba)
+#define SMBHSTADD	(4 + i801_smba)
+#define SMBHSTDAT0	(5 + i801_smba)
+#define SMBHSTDAT1	(6 + i801_smba)
+#define SMBBLKDAT	(7 + i801_smba)
+#define SMBPEC		(8 + i801_smba)	/* ICH4 only */
+#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 only */
+#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 only */
 
 /* PCI Address Constants */
-#define SMBBA     0x020
-#define SMBHSTCFG 0x040
-#define SMBREV    0x008
+#define SMBBA		0x020
+#define SMBHSTCFG	0x040
+#define SMBREV		0x008
 
 /* Host configuration bits for SMBHSTCFG */
-#define SMBHSTCFG_HST_EN      1
-#define SMBHSTCFG_SMB_SMI_EN  2
-#define SMBHSTCFG_I2C_EN      4
+#define SMBHSTCFG_HST_EN	1
+#define SMBHSTCFG_SMB_SMI_EN	2
+#define SMBHSTCFG_I2C_EN	4
 
 /* Other settings */
-#define MAX_TIMEOUT 100
-#define ENABLE_INT9 0	/* set to 0x01 to enable - untested */
+#define MAX_TIMEOUT		100
+#define ENABLE_INT9		0	/* set to 0x01 to enable - untested */
 
 /* I801 command constants */
-#define I801_QUICK          0x00
-#define I801_BYTE           0x04
-#define I801_BYTE_DATA      0x08
-#define I801_WORD_DATA      0x0C
-#define I801_PROC_CALL      0x10	/* later chips only, unimplemented */
-#define I801_BLOCK_DATA     0x14
-#define I801_I2C_BLOCK_DATA 0x18	/* unimplemented */
-#define I801_BLOCK_LAST     0x34
-#define I801_I2C_BLOCK_LAST 0x38	/* unimplemented */
-#define I801_START          0x40
-#define I801_PEC_EN         0x80	/* ICH4 only */
+#define I801_QUICK		0x00
+#define I801_BYTE		0x04
+#define I801_BYTE_DATA		0x08
+#define I801_WORD_DATA		0x0C
+#define I801_PROC_CALL		0x10	/* later chips only, unimplemented */
+#define I801_BLOCK_DATA		0x14
+#define I801_I2C_BLOCK_DATA	0x18	/* unimplemented */
+#define I801_BLOCK_LAST		0x34
+#define I801_I2C_BLOCK_LAST	0x38	/* unimplemented */
+#define I801_START		0x40
+#define I801_PEC_EN		0x80	/* ICH4 only */
 
 /* insmod parameters */
 
@@ -119,10 +102,6 @@
 		 "Forcibly enable the I801 at the given address. "
 		 "EXTREMELY DANGEROUS!");
 
-
-
-
-
 static void i801_do_pause(unsigned int amount);
 static int i801_transaction(void);
 static int i801_block_transaction(union i2c_smbus_data *data,
@@ -135,7 +114,6 @@
 static int i801_setup(struct pci_dev *dev)
 {
 	int error_return = 0;
-	int *num = supported;
 	unsigned char temp;
 
 	/* Note: we keep on searching until we have found 'function 3' */
@@ -143,101 +121,90 @@
 		return -ENODEV;
 
 	I801_dev = dev;
-	isich4 = *num == PCI_DEVICE_ID_INTEL_82801DB_SMBUS;
+	if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3)
+		isich4 = 1;
+	else
+		isich4 = 0;
 
-/* Determine the address of the SMBus areas */
+	/* Determine the address of the SMBus areas */
 	if (force_addr) {
 		i801_smba = force_addr & 0xfff0;
 	} else {
 		pci_read_config_word(I801_dev, SMBBA, &i801_smba);
 		i801_smba &= 0xfff0;
 		if(i801_smba == 0) {
-			printk(KERN_ERR "i2c-i801.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+			dev_err(&dev->dev, "SMB base address uninitialized"
+				"- upgrade BIOS or use force_addr=0xaddr\n");
 			return -ENODEV;
 		}
 	}
 
-	if (check_region(i801_smba, (isich4 ? 16 : 8))) {
-		printk
-		    (KERN_ERR "i2c-i801.o: I801_smb region 0x%x already in use!\n",
-		     i801_smba);
-		error_return = -ENODEV;
+	if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) {
+		dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n",
+			i801_smba);
+		error_return = -EBUSY;
 		goto END;
 	}
 
 	pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
 	temp &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */
 	pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
-/* If force_addr is set, we program the new address here. Just to make
-   sure, we disable the device first. */
+
+	/* If force_addr is set, we program the new address here. Just to make
+	   sure, we disable the device first. */
 	if (force_addr) {
 		pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe);
 		pci_write_config_word(I801_dev, SMBBA, i801_smba);
 		pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01);
-		printk
-		    (KERN_WARNING "i2c-i801.o: WARNING: I801 SMBus interface set to new "
-		     "address %04x!\n", i801_smba);
+		dev_warn(&dev->dev, "WARNING: I801 SMBus interface set to "
+			"new address %04x!\n", i801_smba);
 	} else if ((temp & 1) == 0) {
 		pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1);
-		printk(KERN_WARNING "i2c-i801.o: enabling SMBus device\n");
+		dev_warn(&dev->dev, "enabling SMBus device\n");
 	}
 
-	request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus");
-
-#ifdef DEBUG
 	if (temp & 0x02)
-		printk
-		    (KERN_DEBUG "i2c-i801.o: I801 using Interrupt SMI# for SMBus.\n");
+		dev_dbg(&dev->dev, "I801 using Interrupt SMI# for SMBus.\n");
 	else
-		printk
-		    (KERN_DEBUG "i2c-i801.o: I801 using PCI Interrupt for SMBus.\n");
+		dev_dbg(&dev->dev, "I801 using PCI Interrupt for SMBus.\n");
 
 	pci_read_config_byte(I801_dev, SMBREV, &temp);
-	printk(KERN_DEBUG "i2c-i801.o: SMBREV = 0x%X\n", temp);
-	printk(KERN_DEBUG "i2c-i801.o: I801_smba = 0x%X\n", i801_smba);
-#endif				/* DEBUG */
+	dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
+	dev_dbg(&dev->dev, "I801_smba = 0x%X\n", i801_smba);
 
-      END:
+END:
 	return error_return;
 }
 
 
-void i801_do_pause(unsigned int amount)
+static void i801_do_pause(unsigned int amount)
 {
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(amount);
 }
 
-int i801_transaction(void)
+static int i801_transaction(void)
 {
 	int temp;
 	int result = 0;
 	int timeout = 0;
 
-#ifdef DEBUG
-	printk
-	    (KERN_DEBUG "i2c-i801.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
-	     "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
-	     inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-#endif
+	dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x,"
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
 
 	/* Make sure the SMBus host is ready to start transmitting */
 	/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
 	if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-#ifdef DEBUG
-		printk(KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n",
-		       temp);
-#endif
+		dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting... \n",
+			temp);
 		outb_p(temp, SMBHSTSTS);
 		if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-#ifdef DEBUG
-			printk(KERN_DEBUG "i2c-i801.o: Failed! (%02x)\n", temp);
-#endif
+			dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp);
 			return -1;
 		} else {
-#ifdef DEBUG
-			printk(KERN_DEBUG "i2c-i801.o: Successfull!\n");
-#endif
+			dev_dbg(&I801_dev->dev, "Successfull!\n");
 		}
 	}
 
@@ -251,76 +218,64 @@
 
 	/* If the SMBus is still busy, we give up */
 	if (timeout >= MAX_TIMEOUT) {
-#ifdef DEBUG
-		printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n");
+		dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
 		result = -1;
-#endif
 	}
 
 	if (temp & 0x10) {
 		result = -1;
-#ifdef DEBUG
-		printk(KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n");
-#endif
+		dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n");
 	}
 
 	if (temp & 0x08) {
 		result = -1;
-		printk
-		    (KERN_ERR "i2c-i801.o: Bus collision! SMBus may be locked until next hard\n"
-		     "reset. (sorry!)\n");
+		dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked "
+			"until next hard reset. (sorry!)\n");
 		/* Clock stops and slave is stuck in mid-transmission */
 	}
 
 	if (temp & 0x04) {
 		result = -1;
-#ifdef DEBUG
-		printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n");
-#endif
+		dev_dbg(&I801_dev->dev, "Error: no response!\n");
 	}
 
 	if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
 		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
 
 	if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-#ifdef DEBUG
-		printk
-		    (KERN_DEBUG "i2c-i801.o: Failed reset at end of transaction (%02x)\n",
-		     temp);
-#endif
+		dev_dbg(&I801_dev->dev, "Failed reset at end of transaction"
+			"(%02x)\n", temp);
 	}
-#ifdef DEBUG
-	printk
-	    (KERN_DEBUG "i2c-i801.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
-	     "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
-	     inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-#endif
+	dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
 	return result;
 }
 
 /* All-inclusive block transaction function */
-int i801_block_transaction(union i2c_smbus_data *data, char read_write, 
-                           int command)
+static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+				  int command)
 {
 	int i, len;
 	int smbcmd;
 	int temp;
 	int result = 0;
 	int timeout;
-        unsigned char hostc, errmask;
+	unsigned char hostc, errmask;
 
-        if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
-                if (read_write == I2C_SMBUS_WRITE) {
-                        /* set I2C_EN bit in configuration register */
-                        pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
-                        pci_write_config_byte(I801_dev, SMBHSTCFG, 
-                                              hostc | SMBHSTCFG_I2C_EN);
-                } else {
-                        printk("i2c-i801.o: "
-                               "I2C_SMBUS_I2C_BLOCK_READ not supported!\n");
-                        return -1;
-                }
-        }
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+		if (read_write == I2C_SMBUS_WRITE) {
+			/* set I2C_EN bit in configuration register */
+			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
+			pci_write_config_byte(I801_dev, SMBHSTCFG,
+					      hostc | SMBHSTCFG_I2C_EN);
+		} else {
+			dev_err(&I801_dev->dev,
+				"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
+			return -1;
+		}
+	}
 
 	if (read_write == I2C_SMBUS_WRITE) {
 		len = data->block[0];
@@ -343,60 +298,43 @@
 			smbcmd = I801_BLOCK_LAST;
 		else
 			smbcmd = I801_BLOCK_DATA;
-#if 0 /* now using HW PEC */
-		if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC)
-			smbcmd |= I801_PEC_EN;
-#endif
 		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
 
-#ifdef DEBUG
-		printk
-		    (KERN_DEBUG "i2c-i801.o: Block (pre %d): CNT=%02x, CMD=%02x, ADD=%02x, "
-		     "DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT),
-		     inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-		     inb_p(SMBBLKDAT));
-#endif
+		dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
+			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
 
 		/* Make sure the SMBus host is ready to start transmitting */
 		temp = inb_p(SMBHSTSTS);
-                if (i == 1) {
-                    /* Erronenous conditions before transaction: 
-                     * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
-                    errmask=0x9f; 
-                } else {
-                    /* Erronenous conditions during transaction: 
-                     * Failed, Bus_Err, Dev_Err, Intr */
-                    errmask=0x1e; 
-                }
+		if (i == 1) {
+			/* Erronenous conditions before transaction: 
+			 * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
+			errmask=0x9f; 
+		} else {
+			/* Erronenous conditions during transaction: 
+			 * Failed, Bus_Err, Dev_Err, Intr */
+			errmask=0x1e; 
+		}
 		if (temp & errmask) {
-#ifdef DEBUG
-			printk
-			    (KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n",
-			     temp);
-#endif
+			dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
+				"Resetting... \n", temp);
 			outb_p(temp, SMBHSTSTS);
 			if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
-				printk
-				    (KERN_ERR "i2c-i801.o: Reset failed! (%02x)\n",
-				     temp);
+				dev_err(&I801_dev->dev,
+					"Reset failed! (%02x)\n", temp);
 				result = -1;
                                 goto END;
 			}
 			if (i != 1) {
-                                result = -1;  /* if die in middle of block transaction, fail */
-                                goto END;
-                        }
+				/* if die in middle of block transaction, fail */
+				result = -1;
+				goto END;
+			}
 		}
 
-		if (i == 1) {
-#if 0 /* #ifdef HAVE_PEC (now using HW PEC) */
-			if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) {
-				if(read_write == I2C_SMBUS_WRITE)
-					outb_p(data->block[len + 1], SMBPEC);
-			}
-#endif
+		if (i == 1)
 			outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
-		}
 
 		/* We will always wait for a fraction of a second! */
 		timeout = 0;
@@ -410,25 +348,19 @@
 		/* If the SMBus is still busy, we give up */
 		if (timeout >= MAX_TIMEOUT) {
 			result = -1;
-#ifdef DEBUG
-			printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n");
-#endif
+			dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
 		}
 
 		if (temp & 0x10) {
 			result = -1;
-#ifdef DEBUG
-			printk
-			    (KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n");
-#endif
+			dev_dbg(&I801_dev->dev,
+				"Error: Failed bus transaction\n");
 		} else if (temp & 0x08) {
 			result = -1;
-			printk(KERN_ERR "i2c-i801.o: Bus collision!\n");
+			dev_err(&I801_dev->dev, "Bus collision!\n");
 		} else if (temp & 0x04) {
 			result = -1;
-#ifdef DEBUG
-			printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n");
-#endif
+			dev_dbg(&I801_dev->dev, "Error: no response!\n");
 		}
 
 		if (i == 1 && read_write == I2C_SMBUS_READ) {
@@ -440,7 +372,7 @@
 			data->block[0] = len;
 		}
 
-                /* Retrieve/store value in SMBBLKDAT */
+		/* Retrieve/store value in SMBBLKDAT */
 		if (read_write == I2C_SMBUS_READ)
 			data->block[i] = inb_p(SMBBLKDAT);
 		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
@@ -448,18 +380,15 @@
 		if ((temp & 0x9e) != 0x00)
 			outb_p(temp, SMBHSTSTS);  /* signals SMBBLKDAT ready */
 
-#ifdef DEBUG
 		if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
-			printk
-			    (KERN_DEBUG "i2c-i801.o: Bad status (%02x) at end of transaction\n",
-			     temp);
-		}
-		printk
-		    (KERN_DEBUG "i2c-i801.o: Block (post %d): CNT=%02x, CMD=%02x, ADD=%02x, "
-		     "DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT),
-		     inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-		     inb_p(SMBBLKDAT));
-#endif
+			dev_dbg(&I801_dev->dev,
+				"Bad status (%02x) at end of transaction\n",
+				temp);
+		}
+		dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
+			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
 
 		if (result < 0)
 			goto END;
@@ -476,29 +405,24 @@
 			   && (timeout++ < MAX_TIMEOUT));
 
 		if (timeout >= MAX_TIMEOUT) {
-			printk(KERN_DEBUG "i2c-i801.o: PEC Timeout!\n");
+			dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
 		}
-#if 0 /* now using HW PEC */
-		if(read_write == I2C_SMBUS_READ) {
-			data->block[len + 1] = inb_p(SMBPEC);
-		}
-#endif
 		outb_p(temp, SMBHSTSTS); 
 	}
 #endif
-        result = 0;
+	result = 0;
 END:
-        if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
-                /* restore saved configuration register value */
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+		/* restore saved configuration register value */
 		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
-        }
+	}
 	return result;
 }
 
 /* Return -1 on error. */
-s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
-		char read_write, u8 command, int size,
-		union i2c_smbus_data * data)
+static s32 i801_access(struct i2c_adapter * adap, u16 addr,
+		       unsigned short flags, char read_write, u8 command,
+		       int size, union i2c_smbus_data * data)
 {
 	int hwpec = 0;
 	int block = 0;
@@ -554,7 +478,7 @@
 		break;
 	case I2C_SMBUS_PROC_CALL:
 	default:
-		printk(KERN_ERR "i2c-i801.o: Unsupported transaction %d\n", size);
+		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
 		return -1;
 	}
 
@@ -600,7 +524,7 @@
 }
 
 
-u32 i801_func(struct i2c_adapter *adapter)
+static u32 i801_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
 	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
@@ -627,8 +551,6 @@
 	.algo		= &smbus_algorithm,
 };
 
-
-
 static struct pci_device_id i801_ids[] __devinitdata = {
 	{
 		.vendor =	PCI_VENDOR_ID_INTEL,
@@ -650,13 +572,13 @@
 	},
 	{
 		.vendor =	PCI_VENDOR_ID_INTEL,
-		.device =	PCI_DEVICE_ID_INTEL_82801CA_SMBUS,
+		.device =	PCI_DEVICE_ID_INTEL_82801CA_3,
 		.subvendor =	PCI_ANY_ID,
 		.subdevice =	PCI_ANY_ID,
 	},
 	{
 		.vendor =	PCI_VENDOR_ID_INTEL,
-		.device =	PCI_DEVICE_ID_INTEL_82801DB_SMBUS,
+		.device =	PCI_DEVICE_ID_INTEL_82801DB_3,
 		.subvendor =	PCI_ANY_ID,
 		.subdevice =	PCI_ANY_ID,
 	},
@@ -667,8 +589,8 @@
 {
 
 	if (i801_setup(dev)) {
-		printk
-		    (KERN_WARNING "i2c-i801.o: I801 not detected, module not inserted.\n");
+		dev_warn(&dev->dev,
+			"I801 not detected, module not inserted.\n");
 		return -ENODEV;
 	}
 
@@ -694,22 +616,21 @@
 
 static int __init i2c_i801_init(void)
 {
-	printk(KERN_INFO "i2c-i801.o version %s (%s)\n", I2C_VERSION, I2C_DATE);
+	printk(KERN_INFO "i2c-i801 version %s (%s)\n", I2C_VERSION, I2C_DATE);
 	return pci_module_init(&i801_driver);
 }
 
-
 static void __exit i2c_i801_exit(void)
 {
 	pci_unregister_driver(&i801_driver);
 	release_region(i801_smba, (isich4 ? 16 : 8));
 }
 
-
-
-MODULE_AUTHOR
-    ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+		"Philip Edelbrock <phil@netroedge.com>, "
+		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
 MODULE_DESCRIPTION("I801 SMBus driver");
+MODULE_LICENSE("GPL");
 
 module_init(i2c_i801_init);
 module_exit(i2c_i801_exit);
diff -urN linux-2.5.65-bk1/drivers/i2c/busses/i2c-isa.c linux-2.5.65-bk2/drivers/i2c/busses/i2c-isa.c
--- linux-2.5.65-bk1/drivers/i2c/busses/i2c-isa.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/drivers/i2c/busses/i2c-isa.c	Mon Mar 31 12:39:50 2003
@@ -0,0 +1,62 @@
+/*
+    i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware
+            monitoring
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This implements an i2c algorithm/adapter for ISA bus. Not that this is
+   on first sight very useful; almost no functionality is preserved.
+   Except that it makes writing drivers for chips which can be on both
+   the SMBus and the ISA bus very much easier. See lm78.c for an example
+   of this. */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+
+/* This is the actual algorithm we define */
+static struct i2c_algorithm isa_algorithm = {
+	.name		= "ISA bus algorithm",
+	.id		= I2C_ALGO_ISA,
+};
+
+/* There can only be one... */
+static struct i2c_adapter isa_adapter = {
+	.owner		= THIS_MODULE,
+	.name		= "ISA main adapter",
+	.id		= I2C_ALGO_ISA | I2C_HW_ISA,
+	.algo		= &isa_algorithm,
+};
+
+static int __init i2c_isa_init(void)
+{
+	return i2c_add_adapter(&isa_adapter);
+}
+
+static void __exit i2c_isa_exit(void)
+{
+	i2c_del_adapter(&isa_adapter);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+MODULE_DESCRIPTION("ISA bus access through i2c");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_isa_init);
+module_exit(i2c_isa_exit);
diff -urN linux-2.5.65-bk1/drivers/i2c/busses/i2c-piix4.c linux-2.5.65-bk2/drivers/i2c/busses/i2c-piix4.c
--- linux-2.5.65-bk1/drivers/i2c/busses/i2c-piix4.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/drivers/i2c/busses/i2c-piix4.c	Mon Mar 31 12:39:50 2003
@@ -28,6 +28,8 @@
    Note: we assume there can only be one device, with one SMBus interface.
 */
 
+/* #define DEBUG 1 */
+
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/pci.h>
@@ -49,37 +51,37 @@
 };
 
 /* PIIX4 SMBus address offsets */
-#define SMBHSTSTS (0 + piix4_smba)
-#define SMBHSLVSTS (1 + piix4_smba)
-#define SMBHSTCNT (2 + piix4_smba)
-#define SMBHSTCMD (3 + piix4_smba)
-#define SMBHSTADD (4 + piix4_smba)
-#define SMBHSTDAT0 (5 + piix4_smba)
-#define SMBHSTDAT1 (6 + piix4_smba)
-#define SMBBLKDAT (7 + piix4_smba)
-#define SMBSLVCNT (8 + piix4_smba)
-#define SMBSHDWCMD (9 + piix4_smba)
-#define SMBSLVEVT (0xA + piix4_smba)
-#define SMBSLVDAT (0xC + piix4_smba)
+#define SMBHSTSTS	(0 + piix4_smba)
+#define SMBHSLVSTS	(1 + piix4_smba)
+#define SMBHSTCNT	(2 + piix4_smba)
+#define SMBHSTCMD	(3 + piix4_smba)
+#define SMBHSTADD	(4 + piix4_smba)
+#define SMBHSTDAT0	(5 + piix4_smba)
+#define SMBHSTDAT1	(6 + piix4_smba)
+#define SMBBLKDAT	(7 + piix4_smba)
+#define SMBSLVCNT	(8 + piix4_smba)
+#define SMBSHDWCMD	(9 + piix4_smba)
+#define SMBSLVEVT	(0xA + piix4_smba)
+#define SMBSLVDAT	(0xC + piix4_smba)
 
 /* PCI Address Constants */
-#define SMBBA     0x090
-#define SMBHSTCFG 0x0D2
-#define SMBSLVC   0x0D3
-#define SMBSHDW1  0x0D4
-#define SMBSHDW2  0x0D5
-#define SMBREV    0x0D6
+#define SMBBA		0x090
+#define SMBHSTCFG	0x0D2
+#define SMBSLVC		0x0D3
+#define SMBSHDW1	0x0D4
+#define SMBSHDW2	0x0D5
+#define SMBREV		0x0D6
 
 /* Other settings */
-#define MAX_TIMEOUT 500
-#define  ENABLE_INT9 0
+#define MAX_TIMEOUT	500
+#define  ENABLE_INT9	0
 
 /* PIIX4 constants */
-#define PIIX4_QUICK      0x00
-#define PIIX4_BYTE       0x04
-#define PIIX4_BYTE_DATA  0x08
-#define PIIX4_WORD_DATA  0x0C
-#define PIIX4_BLOCK_DATA 0x14
+#define PIIX4_QUICK		0x00
+#define PIIX4_BYTE		0x04
+#define PIIX4_BYTE_DATA		0x08
+#define PIIX4_WORD_DATA		0x0C
+#define PIIX4_BLOCK_DATA	0x14
 
 /* insmod parameters */
 
@@ -102,6 +104,7 @@
 
 
 static unsigned short piix4_smba = 0;
+static struct i2c_adapter piix4_adapter;
 
 /*
  * Get DMI information.
@@ -125,18 +128,17 @@
 	if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data)
 		return -ENODEV;
 
-	printk(KERN_INFO "i2c-piix4.o: Found %s device\n", PIIX4_dev->dev.name);
+	dev_info(&PIIX4_dev->dev, "Found %s device\n", PIIX4_dev->dev.name);
 
 	if(ibm_dmi_probe()) {
-		printk
-		  (KERN_ERR "i2c-piix4.o: IBM Laptop detected; this module may corrupt\n");
-		printk
-		  (KERN_ERR "             your serial eeprom! Refusing to load module!\n");
-		 error_return = -EPERM;
-		 goto END;
+		dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module "
+			"may corrupt your serial eeprom! Refusing to load "
+			"module!\n");
+		error_return = -EPERM;
+		goto END;
 	}
 
-/* Determine the address of the SMBus areas */
+	/* Determine the address of the SMBus areas */
 	if (force_addr) {
 		piix4_smba = force_addr & 0xfff0;
 		force = 0;
@@ -144,75 +146,68 @@
 		pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
 		piix4_smba &= 0xfff0;
 		if(piix4_smba == 0) {
-			printk(KERN_ERR "i2c-piix4.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+			dev_err(&PIIX4_dev->dev, "SMB base address "
+				"uninitialized - upgrade BIOS or use "
+				"force_addr=0xaddr\n");
 			return -ENODEV;
 		}
 	}
 
-	if (check_region(piix4_smba, 8)) {
-		printk
-		    (KERN_ERR "i2c-piix4.o: SMB region 0x%x already in use!\n",
-		     piix4_smba);
+	if (!request_region(piix4_smba, 8, "piix4-smbus")) {
+		dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n",
+			piix4_smba);
 		error_return = -ENODEV;
 		goto END;
 	}
 
 	pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
-/* If force_addr is set, we program the new address here. Just to make
-   sure, we disable the PIIX4 first. */
+	/* If force_addr is set, we program the new address here. Just to make
+	   sure, we disable the PIIX4 first. */
 	if (force_addr) {
 		pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe);
 		pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba);
 		pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01);
-		printk
-		    (KERN_INFO "i2c-piix4.o: WARNING: SMBus interface set to new "
-		     "address %04x!\n", piix4_smba);
+		dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to "
+			"new address %04x!\n", piix4_smba);
 	} else if ((temp & 1) == 0) {
 		if (force) {
-/* This should never need to be done, but has been noted that
-   many Dell machines have the SMBus interface on the PIIX4
-   disabled!? NOTE: This assumes I/O space and other allocations WERE
-   done by the Bios!  Don't complain if your hardware does weird 
-   things after enabling this. :') Check for Bios updates before
-   resorting to this.  */
+			/* This should never need to be done, but has been
+			 * noted that many Dell machines have the SMBus
+			 * interface on the PIIX4 disabled!? NOTE: This assumes
+			 * I/O space and other allocations WERE done by the
+			 * Bios!  Don't complain if your hardware does weird
+			 * things after enabling this. :') Check for Bios
+			 * updates before resorting to this.
+			 */
 			pci_write_config_byte(PIIX4_dev, SMBHSTCFG,
 					      temp | 1);
-			printk
-			    (KERN_NOTICE "i2c-piix4.o: WARNING: SMBus interface has been FORCEFULLY "
-			     "ENABLED!\n");
+			dev_printk(KERN_NOTICE, &PIIX4_dev->dev,
+				"WARNING: SMBus interface has been "
+				"FORCEFULLY ENABLED!\n");
 		} else {
-			printk
-			    (KERN_ERR "i2c-piix4.o: Host SMBus controller not enabled!\n");
+			dev_err(&PIIX4_dev->dev,
+				"Host SMBus controller not enabled!\n");
 			error_return = -ENODEV;
 			goto END;
 		}
 	}
 
-	/* Everything is happy, let's grab the memory and set things up. */
-	request_region(piix4_smba, 8, "piix4-smbus");
-
-#ifdef DEBUG
 	if ((temp & 0x0E) == 8)
-		printk
-		    (KERN_DEBUG "i2c-piix4.o: Using Interrupt 9 for SMBus.\n");
+		dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n");
 	else if ((temp & 0x0E) == 0)
-		printk
-		    (KERN_DEBUG "i2c-piix4.o: Using Interrupt SMI# for SMBus.\n");
+		dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n");
 	else
-		printk
-		    (KERN_ERR "i2c-piix4.o: Illegal Interrupt configuration (or code out "
-		     "of date)!\n");
+		dev_err(&PIIX4_dev->dev, "Illegal Interrupt configuration "
+			"(or code out of date)!\n");
 
 	pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
-	printk(KERN_DEBUG "i2c-piix4.o: SMBREV = 0x%X\n", temp);
-	printk(KERN_DEBUG "i2c-piix4.o: SMBA = 0x%X\n", piix4_smba);
-#endif				/* DEBUG */
+	dev_dbg(&PIIX4_dev->dev, "SMBREV = 0x%X\n", temp);
+	dev_dbg(&PIIX4_dev->dev, "SMBA = 0x%X\n", piix4_smba);
 
-      END:
+END:
 	return error_return;
 }
 
-
 /* Internally used pause function */
 static void piix4_do_pause(unsigned int amount)
 {
@@ -227,29 +222,21 @@
 	int result = 0;
 	int timeout = 0;
 
-#ifdef DEBUG
-	printk
-	    (KERN_DEBUG "i2c-piix4.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
-	     "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
-	     inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-#endif
+	dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
 
 	/* Make sure the SMBus host is ready to start transmitting */
 	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-#ifdef DEBUG
-		printk(KERN_DEBUG "i2c-piix4.o: SMBus busy (%02x). Resetting... \n",
-		       temp);
-#endif
+		dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
+			"Resetting... \n", temp);
 		outb_p(temp, SMBHSTSTS);
 		if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-#ifdef DEBUG
-			printk(KERN_ERR "i2c-piix4.o: Failed! (%02x)\n", temp);
-#endif
+			dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
 			return -1;
 		} else {
-#ifdef DEBUG
-			printk(KERN_DEBUG "i2c-piix4.o: Successfull!\n");
-#endif
+			dev_dbg(&piix4_adapter.dev, "Successfull!\n");
 		}
 	}
 
@@ -262,50 +249,40 @@
 		temp = inb_p(SMBHSTSTS);
 	} while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
 
-#ifdef DEBUG
 	/* If the SMBus is still busy, we give up */
 	if (timeout >= MAX_TIMEOUT) {
-		printk(KERN_ERR "i2c-piix4.o: SMBus Timeout!\n");
+		dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
 		result = -1;
 	}
-#endif
 
 	if (temp & 0x10) {
 		result = -1;
-#ifdef DEBUG
-		printk(KERN_ERR "i2c-piix4.o: Error: Failed bus transaction\n");
-#endif
+		dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
 	}
 
 	if (temp & 0x08) {
 		result = -1;
-		printk
-		    (KERN_ERR "i2c-piix4.o: Bus collision! SMBus may be locked until next hard\n"
-		     "reset. (sorry!)\n");
+		dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
+			"locked until next hard reset. (sorry!)\n");
 		/* Clock stops and slave is stuck in mid-transmission */
 	}
 
 	if (temp & 0x04) {
 		result = -1;
-#ifdef DEBUG
-		printk(KERN_ERR "i2c-piix4.o: Error: no response!\n");
-#endif
+		dev_err(&piix4_adapter.dev, "Error: no response!\n");
 	}
 
 	if (inb_p(SMBHSTSTS) != 0x00)
 		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
 
-#ifdef DEBUG
 	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		printk
-		    (KERN_ERR "i2c-piix4.o: Failed reset at end of transaction (%02x)\n",
-		     temp);
-	}
-	printk
-	    (KERN_DEBUG "i2c-piix4.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
-	     "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
-	     inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-#endif
+		dev_err(&piix4_adapter.dev, "Failed reset at end of "
+			"transaction (%02x)\n", temp);
+	}
+	dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
 	return result;
 }
 
@@ -318,8 +295,7 @@
 
 	switch (size) {
 	case I2C_SMBUS_PROC_CALL:
-		printk
-		    (KERN_ERR "i2c-piix4.o: I2C_SMBUS_PROC_CALL not supported!\n");
+		dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
 		return -1;
 	case I2C_SMBUS_QUICK:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
@@ -402,7 +378,6 @@
 	return 0;
 }
 
-
 static u32 piix4_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
@@ -424,8 +399,6 @@
 	.algo		= &smbus_algorithm,
 };
 
-
-
 static struct pci_device_id piix4_ids[] __devinitdata = {
 	{
 		.vendor =	PCI_VENDOR_ID_INTEL,
@@ -468,7 +441,7 @@
 static int __devinit piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	int retval;
-	
+
 	retval = piix4_setup(dev, id);
 	if (retval)
 		return retval;
@@ -499,7 +472,7 @@
 
 static int __init i2c_piix4_init(void)
 {
-	printk("i2c-piix4.o version %s (%s)\n", I2C_VERSION, I2C_DATE);
+	printk(KERN_INFO "i2c-piix4 version %s (%s)\n", I2C_VERSION, I2C_DATE);
 	return pci_module_init(&piix4_driver);
 }
 
@@ -510,8 +483,6 @@
 	release_region(piix4_smba, 8);
 }
 
-
-
 MODULE_AUTHOR
     ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
 MODULE_DESCRIPTION("PIIX4 SMBus driver");
diff -urN linux-2.5.65-bk1/drivers/i2c/chips/adm1021.c linux-2.5.65-bk2/drivers/i2c/chips/adm1021.c
--- linux-2.5.65-bk1/drivers/i2c/chips/adm1021.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/drivers/i2c/chips/adm1021.c	Mon Mar 31 12:39:50 2003
@@ -93,9 +93,9 @@
 
 /* Initial values */
 
-/* Note: Eventhough I left the low and high limits named os and hyst, 
+/* Note: Even though I left the low and high limits named os and hyst, 
 they don't quite work like a thermostat the way the LM75 does.  I.e., 
-a lower temp than THYST actuall triggers an alarm instead of 
+a lower temp than THYST actually triggers an alarm instead of 
 clearing it.  Weird, ey?   --Phil  */
 #define adm1021_INIT_TOS 60
 #define adm1021_INIT_THYST 20
diff -urN linux-2.5.65-bk1/drivers/i2c/chips/lm75.c linux-2.5.65-bk2/drivers/i2c/chips/lm75.c
--- linux-2.5.65-bk1/drivers/i2c/chips/lm75.c	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/drivers/i2c/chips/lm75.c	Mon Mar 31 12:39:50 2003
@@ -25,7 +25,7 @@
 #include <linux/i2c-proc.h>
 
 
-#define LM75_SYSCTL_TEMP 1200	/* Degrees Celcius * 10 */
+#define LM75_SYSCTL_TEMP 1200	/* Degrees Celsius * 10 */
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { SENSORS_I2C_END };
diff -urN linux-2.5.65-bk1/drivers/i2c/i2c-algo-pcf.c linux-2.5.65-bk2/drivers/i2c/i2c-algo-pcf.c
--- linux-2.5.65-bk1/drivers/i2c/i2c-algo-pcf.c	Mon Mar 17 13:44:38 2003
+++ linux-2.5.65-bk2/drivers/i2c/i2c-algo-pcf.c	Mon Mar 31 12:39:50 2003
@@ -152,7 +152,7 @@
 
 	/* load own address in S0, effective address is (own << 1)	*/
 	i2c_outb(adap, get_own(adap));
-	/* check it's realy writen */
+	/* check it's really written */
 	if ((temp = i2c_inb(adap)) != get_own(adap)) {
 		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
 		return -ENXIO;
@@ -168,7 +168,7 @@
 
 	/* load clock register S2					*/
 	i2c_outb(adap, get_clock(adap));
-	/* check it's realy writen, the only 5 lowest bits does matter */
+	/* check it's really written, the only 5 lowest bits does matter */
 	if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
 		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
 		return -ENXIO;
@@ -177,7 +177,7 @@
 	/* Enable serial interface, idle, S0 selected			*/
 	set_pcf(adap, 1, I2C_PCF_IDLE);
 
-	/* check to see PCF is realy idled and we can access status register */
+	/* check to see PCF is really idled and we can access status register */
 	if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
 		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
 		return -ENXIO;
diff -urN linux-2.5.65-bk1/drivers/i2c/i2c-core.c linux-2.5.65-bk2/drivers/i2c/i2c-core.c
--- linux-2.5.65-bk1/drivers/i2c/i2c-core.c	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/drivers/i2c/i2c-core.c	Mon Mar 31 12:39:50 2003
@@ -53,6 +53,16 @@
 #endif /* CONFIG_PROC_FS */
 
 
+int i2c_device_probe(struct device *dev)
+{
+	return -ENODEV;
+}
+
+int i2c_device_remove(struct device *dev)
+{
+	return 0;
+}
+
 /* ---------------------------------------------------
  * registering functions 
  * --------------------------------------------------- 
@@ -204,6 +214,16 @@
 	drivers[i] = driver;
 	
 	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
+
+	/* add the driver to the list of i2c drivers in the driver core */
+	driver->driver.name = driver->name;
+	driver->driver.bus = &i2c_bus_type;
+	driver->driver.probe = i2c_device_probe;
+	driver->driver.remove = i2c_device_remove;
+
+	res = driver_register(&driver->driver);
+	if (res)
+		goto out_unlock;
 	
 	/* now look for instances of driver on our adapters
 	 */
@@ -236,6 +256,8 @@
 		goto out_unlock;
 	}
 
+	driver_unregister(&driver->driver);
+
 	/* Have a look at each adapter, if clients of this driver are still
 	 * attached. If so, detach them to be able to kill the driver 
 	 * afterwards.
diff -urN linux-2.5.65-bk1/drivers/i2c/i2c-proc.c linux-2.5.65-bk2/drivers/i2c/i2c-proc.c
--- linux-2.5.65-bk1/drivers/i2c/i2c-proc.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/drivers/i2c/i2c-proc.c	Mon Mar 31 12:39:50 2003
@@ -270,7 +270,7 @@
 }
 
 
-/* This funcion reads or writes a 'real' value (encoded by the combination
+/* This function reads or writes a 'real' value (encoded by the combination
    of an integer and a magnitude, the last is the power of ten the value
    should be divided with) to a /proc/sys directory. To use this function,
    you must (before registering the ctl_table) set the extra2 field to the
diff -urN linux-2.5.65-bk1/drivers/ide/pci/piix.c linux-2.5.65-bk2/drivers/ide/pci/piix.c
--- linux-2.5.65-bk1/drivers/ide/pci/piix.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/drivers/ide/pci/piix.c	Mon Mar 31 12:39:50 2003
@@ -106,6 +106,7 @@
 #include "ide_modes.h"
 #include "piix.h"
 
+static int no_piix_dma;
 #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -114,7 +115,6 @@
 #define PIIX_MAX_DEVS		5
 static struct pci_dev *piix_devs[PIIX_MAX_DEVS];
 static int n_piix_devs;
-static int no_piix_dma = 0;
 
 /**
  *	piix_get_info		-	fill in /proc for PIIX ide
diff -urN linux-2.5.65-bk1/drivers/macintosh/adb.c linux-2.5.65-bk2/drivers/macintosh/adb.c
--- linux-2.5.65-bk1/drivers/macintosh/adb.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/drivers/macintosh/adb.c	Mon Mar 31 12:39:50 2003
@@ -249,7 +249,7 @@
 	strcpy(current->comm, "kadbprobe");
 
 	sigfillset(&blocked);
-	sicprocmask(SIG_BLOCK, &blocked, NULL);	
+	sigprocmask(SIG_BLOCK, &blocked, NULL);	
 	flush_signals(current);
 
 	printk(KERN_INFO "adb: starting probe task...\n");
diff -urN linux-2.5.65-bk1/drivers/md/md.c linux-2.5.65-bk2/drivers/md/md.c
--- linux-2.5.65-bk1/drivers/md/md.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/drivers/md/md.c	Mon Mar 31 12:39:50 2003
@@ -1735,7 +1735,6 @@
 	mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */
 	mddev->in_sync = 1;
 	
-	md_update_sb(mddev);
 	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 	md_wakeup_thread(mddev->thread);
 	set_capacity(disk, md_size[mdidx(mddev)]<<1);
@@ -1763,7 +1762,6 @@
 			goto out;
 
 		mddev->safemode = 0;
-		md_update_sb(mddev);
 		mddev->ro = 0;
 		set_disk_ro(disk, 0);
 
@@ -3247,7 +3245,7 @@
 {
 	mddev_t *mddev2;
 	unsigned int max_sectors, currspeed = 0,
-		j, window, err;
+		j, window;
 	unsigned long mark[SYNC_MARKS];
 	unsigned long mark_cnt[SYNC_MARKS];
 	int last_mark,m;
@@ -3283,7 +3281,6 @@
 				if (wait_event_interruptible(resync_wait,
 							     mddev2->curr_resync < mddev->curr_resync)) {
 					flush_signals(current);
-					err = -EINTR;
 					mddev_put(mddev2);
 					goto skip;
 				}
@@ -3335,7 +3332,7 @@
 
 		sectors = mddev->pers->sync_request(mddev, j, currspeed < sysctl_speed_limit_min);
 		if (sectors < 0) {
-			err = sectors;
+			set_bit(MD_RECOVERY_ERR, &mddev->recovery);
 			goto out;
 		}
 		atomic_add(sectors, &mddev->recovery_active);
@@ -3372,7 +3369,7 @@
 			 */
 			printk(KERN_INFO "md: md_do_sync() got signal ... exiting\n");
 			flush_signals(current);
-			err = -EINTR;
+			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
 			goto out;
 		}
 
@@ -3398,7 +3395,6 @@
 		}
 	}
 	printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev));
-	err = 0;
 	/*
 	 * this also signals 'finished resyncing' to md_stop
 	 */
@@ -3408,8 +3404,6 @@
 	/* tell personality that we are finished */
 	mddev->pers->sync_request(mddev, max_sectors, 1);
 
-	if (err)
-		set_bit(MD_RECOVERY_ERR, &mddev->recovery);
 	if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
 	    mddev->curr_resync > 2 &&
 	    mddev->curr_resync > mddev->recovery_cp) {
diff -urN linux-2.5.65-bk1/drivers/md/raid1.c linux-2.5.65-bk2/drivers/md/raid1.c
--- linux-2.5.65-bk1/drivers/md/raid1.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/drivers/md/raid1.c	Mon Mar 31 12:39:50 2003
@@ -840,7 +840,8 @@
 			 * we read from here, no need to write
 			 */
 			continue;
-		if (conf->mirrors[i].rdev->in_sync && mddev->in_sync)
+		if (conf->mirrors[i].rdev->in_sync && 
+			r1_bio->sector + (bio->bi_size>>9) <= mddev->recovery_cp)
 			/*
 			 * don't need to write this we are just rebuilding
 			 */
diff -urN linux-2.5.65-bk1/drivers/media/dvb/dvb-core/dvb_demux.c linux-2.5.65-bk2/drivers/media/dvb/dvb-core/dvb_demux.c
--- linux-2.5.65-bk1/drivers/media/dvb/dvb-core/dvb_demux.c	Mon Mar 17 13:43:44 2003
+++ linux-2.5.65-bk2/drivers/media/dvb/dvb-core/dvb_demux.c	Mon Mar 31 12:39:50 2003
@@ -221,7 +221,7 @@
 			return 0;
 		neq|=f->maskandnotmode[i]&xor;
 	}
-	if (f->doneq & !neq)
+	if (f->doneq && !neq)
 		return 0;
 
         return dvbdmxfeed->cb.sec(dvbdmxfeed->secbuf, dvbdmxfeed->seclen, 
diff -urN linux-2.5.65-bk1/drivers/net/3c509.c linux-2.5.65-bk2/drivers/net/3c509.c
--- linux-2.5.65-bk1/drivers/net/3c509.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/drivers/net/3c509.c	Mon Mar 31 12:39:50 2003
@@ -56,6 +56,10 @@
 		v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org>
 		    - Introduce driver model for EISA cards.
 */
+/*
+  FIXES for PC-9800:
+  Shu Iwanaga: 3c569B(PC-9801 C-bus) support
+*/
 
 #define DRV_NAME	"3c509"
 #define DRV_VERSION	"1.19b"
@@ -257,7 +261,7 @@
 };
 #endif /* CONFIG_MCA */
 
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
 static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
@@ -350,7 +354,7 @@
 		if (lp->pmdev)
 			pm_unregister(lp->pmdev);
 #endif
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
 		if (lp->type == EL3_PNP)
 			pnp_device_detach(to_pnp_dev(lp->dev));
 #endif
@@ -368,12 +372,12 @@
 	int ioaddr, irq, if_port;
 	u16 phys_addr[3];
 	static int current_tag;
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
 	static int pnp_cards;
 	struct pnp_dev *idev = NULL;
 #endif /* __ISAPNP__ */
 
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
 	if (nopnp == 1)
 		goto no_pnp;
 
@@ -421,6 +425,9 @@
 no_pnp:
 #endif /* __ISAPNP__ */
 
+#ifdef CONFIG_X86_PC9800
+	id_port = 0x71d0;
+#else
 	/* Select an open I/O location at 0x1*0 to do contention select. */
 	for ( ; id_port < 0x200; id_port += 0x10) {
 		if (check_region(id_port, 1))
@@ -435,6 +442,7 @@
 		printk(" WARNING: No I/O port available for 3c509 activation.\n");
 		return -ENODEV;
 	}
+#endif /* CONFIG_X86_PC9800 */
 	/* Next check for all ISA bus boards by sending the ID sequence to the
 	   ID_PORT.  We find cards past the first by setting the 'current_tag'
 	   on cards as they are found.  Cards with their tag set will not
@@ -465,7 +473,7 @@
 		phys_addr[i] = htons(id_read_eeprom(i));
 	}
 
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
 	if (nopnp == 0) {
 		/* The ISA PnP 3c509 cards respond to the ID sequence.
 		   This check is needed in order not to register them twice. */
@@ -490,9 +498,19 @@
 	{
 		unsigned int iobase = id_read_eeprom(8);
 		if_port = iobase >> 14;
+#ifdef CONFIG_X86_PC9800
+		ioaddr = 0x40d0 + ((iobase & 0x1f) << 8);
+#else
 		ioaddr = 0x200 + ((iobase & 0x1f) << 4);
+#endif
 	}
 	irq = id_read_eeprom(9) >> 12;
+#ifdef CONFIG_X86_PC9800
+	if (irq == 7)
+		irq = 6;
+	else if (irq == 15)
+		irq = 13;
+#endif
 
 	if (!(dev = init_etherdev(NULL, sizeof(struct el3_private))))
 			return -ENOMEM;
@@ -522,7 +540,11 @@
 	outb(0xd0 + ++current_tag, id_port);
 
 	/* Activate the adaptor at the EEPROM location. */
+#ifdef CONFIG_X86_PC9800
+	outb((ioaddr >> 8) | 0xe0, id_port);
+#else
 	outb((ioaddr >> 4) | 0xe0, id_port);
+#endif
 
 	EL3WINDOW(0);
 	if (inw(ioaddr) != 0x6d50) {
@@ -534,7 +556,7 @@
 	/* Free the interrupt so that some other card can use it. */
 	outw(0x0f00, ioaddr + WN0_IRQ);
 
-#ifdef __ISAPNP__	
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
  found:							/* PNP jumps here... */
 #endif /* __ISAPNP__ */
 
@@ -543,7 +565,7 @@
 	dev->irq = irq;
 	dev->if_port = if_port;
 	lp = dev->priv;
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
 	lp->dev = &idev->dev;
 #endif
 
@@ -1388,6 +1410,12 @@
 	outw(0x0001, ioaddr + 4);
 
 	/* Set the IRQ line. */
+#ifdef CONFIG_X86_PC9800
+	if (dev->irq == 6)
+		dev->irq = 7;
+	else if (dev->irq == 13)
+		dev->irq = 15;
+#endif
 	outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
 
 	/* Set the station address in window 2 each time opened. */
@@ -1550,7 +1578,7 @@
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
 MODULE_PARM_DESC(xcvr,"transceiver(s) (0=internal, 1=external)");
 MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
 MODULE_PARM(nopnp, "i");
 MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
 MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
diff -urN linux-2.5.65-bk1/drivers/net/82596.c linux-2.5.65-bk2/drivers/net/82596.c
--- linux-2.5.65-bk1/drivers/net/82596.c	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/drivers/net/82596.c	Mon Mar 31 12:39:50 2003
@@ -646,7 +646,7 @@
 
 	/* change the scp address */
 
-	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp));
+	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
 
 #elif defined(ENABLE_APRICOT)
 
@@ -677,8 +677,8 @@
 		lp->scp.sysbus = 0x00440000;
 #endif
 
-	lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp)));
-	lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb)));
+	lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
+	lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
 	lp->iscp.stat = ISCP_BUSY;
 	lp->cmd_backlog = 0;
 
diff -urN linux-2.5.65-bk1/drivers/net/8390.h linux-2.5.65-bk2/drivers/net/8390.h
--- linux-2.5.65-bk1/drivers/net/8390.h	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/drivers/net/8390.h	Mon Mar 31 12:39:50 2003
@@ -123,7 +123,8 @@
 #define inb_p(port)   in_8(port)
 #define outb_p(val,port)  out_8(port,val)
 
-#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
+#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) || \
+      defined(CONFIG_NET_CBUS)
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 #else
 #define EI_SHIFT(x)	(x)
diff -urN linux-2.5.65-bk1/drivers/net/Kconfig linux-2.5.65-bk2/drivers/net/Kconfig
--- linux-2.5.65-bk1/drivers/net/Kconfig	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/drivers/net/Kconfig	Mon Mar 31 12:39:50 2003
@@ -663,7 +663,7 @@
 	  as <file:Documentation/networking/net-modules.txt>.
 
 config EL3
-	tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
+	tristate "3c509/3c529 (MCA)/3c569B (98)/3c579 \"EtherLink III\" support"
 	depends on NET_VENDOR_3COM && (ISA || EISA || MCA)
 	---help---
 	  If you have a network (Ethernet) card belonging to the 3Com
@@ -932,7 +932,7 @@
 source "drivers/net/tulip/Kconfig"
 
 config AT1700
-	tristate "AT1700/1720 support (EXPERIMENTAL)"
+	tristate "AT1700/1720/RE1000Plus(C-Bus) support (EXPERIMENTAL)"
 	depends on NET_ETHERNET && (ISA || MCA) && EXPERIMENTAL
 	---help---
 	  If you have a network (Ethernet) card of this type, say Y and read
@@ -978,7 +978,7 @@
 
 config NET_ISA
 	bool "Other ISA cards"
-	depends on NET_ETHERNET && ISA
+	depends on NET_ETHERNET && ISA && !X86_PC9800
 	---help---
 	  If your network (Ethernet) card hasn't been mentioned yet and its
 	  bus system (that's the way the cards talks to the other components
@@ -1176,6 +1176,55 @@
 	  the Ethernet-HOWTO, available from
 	  <http://www.linuxdoc.org/docs.html#howto>.
 
+config NET_CBUS
+	bool "NEC PC-9800 C-bus cards"
+	depends on NET_ETHERNET && ISA && X86_PC9800
+	---help---
+	  If your network (Ethernet) card hasn't been mentioned yet and its
+	  bus system (that's the way the cards talks to the other components
+	  of your computer) is NEC PC-9800 C-Bus, say Y.
+
+config NE2K_CBUS
+	tristate "Most NE2000-based Ethernet support"
+	depends on NET_CBUS
+
+config NE2K_CBUS_EGY98
+	bool "Melco EGY-98 support"
+	depends on NE2K_CBUS
+
+config NE2K_CBUS_LGY98
+	bool "Melco LGY-98 support"
+	depends on NE2K_CBUS
+
+config NE2K_CBUS_ICM
+	bool "ICM IF-27xxET support"
+	depends on NE2K_CBUS
+
+config NE2K_CBUS_IOLA98
+	bool "I-O DATA LA-98 support"
+	depends on NE2K_CBUS
+
+config NE2K_CBUS_CNET98EL
+	bool "Contec C-NET(98)E/L support"
+	depends on NE2K_CBUS
+
+config NE2K_CBUS_CNET98EL_IO_BASE
+	hex "C-NET(98)E/L I/O base address (0xaaed or 0x55ed)"
+	depends on NE2K_CBUS_CNET98EL
+	default "0xaaed"
+
+config NE2K_CBUS_ATLA98
+	bool "Allied Telesis LA-98 Support"
+	depends on NE2K_CBUS
+
+config NE2K_CBUS_BDN
+	bool "ELECOM Laneed LD-BDN[123]A Support"
+	depends on NE2K_CBUS
+
+config NE2K_CBUS_NEC108
+	bool "NEC PC-9801-108 Support"
+	depends on NE2K_CBUS
+
 config SKMC
 	tristate "SKnet MCA support"
 	depends on NET_ETHERNET && MCA
@@ -1904,6 +1953,7 @@
 	  82544       PRO/1000 XF Server Adapter           A50484-xxx
 	  82544       PRO/1000 T Desktop Adapter           A62947-xxx
 	  82540       PRO/1000 MT Desktop Adapter          A78408-xxx
+	  82541       PRO/1000 MT Desktop Adapter          C91016-xxx
 	  82545       PRO/1000 MT Server Adapter           A92165-xxx
 	  82546       PRO/1000 MT Dual Port Server Adapter A92111-xxx
 	  82545       PRO/1000 MF Server Adapter           A91622-xxx
diff -urN linux-2.5.65-bk1/drivers/net/Makefile linux-2.5.65-bk2/drivers/net/Makefile
--- linux-2.5.65-bk1/drivers/net/Makefile	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/drivers/net/Makefile	Mon Mar 31 12:39:50 2003
@@ -81,6 +81,7 @@
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_EL2) += 3c503.o 8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390.o
+obj-$(CONFIG_NE2K_CBUS) += ne2k_cbus.o 8390.o
 obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o
 obj-$(CONFIG_HPLAN) += hp.o 8390.o
 obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
diff -urN linux-2.5.65-bk1/drivers/net/Makefile.lib linux-2.5.65-bk2/drivers/net/Makefile.lib
--- linux-2.5.65-bk1/drivers/net/Makefile.lib	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/drivers/net/Makefile.lib	Mon Mar 31 12:39:50 2003
@@ -19,6 +19,7 @@
 obj-$(CONFIG_MACMACE)		+= crc32.o
 obj-$(CONFIG_MIPS_AU1000_ENET)	+= crc32.o
 obj-$(CONFIG_NATSEMI)		+= crc32.o	
+obj-$(CONFIG_NE2K_CBUS)		+= crc32.o
 obj-$(CONFIG_PCMCIA_FMVJ18X)	+= crc32.o
 obj-$(CONFIG_PCMCIA_SMC91C92)	+= crc32.o
 obj-$(CONFIG_PCMCIA_XIRTULIP)	+= crc32.o
diff -urN linux-2.5.65-bk1/drivers/net/Space.c linux-2.5.65-bk2/drivers/net/Space.c
--- linux-2.5.65-bk1/drivers/net/Space.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/drivers/net/Space.c	Mon Mar 31 12:39:50 2003
@@ -233,7 +233,7 @@
 #ifdef CONFIG_E2100		/* Cabletron E21xx series. */
 	{e2100_probe, 0},
 #endif
-#ifdef CONFIG_NE2000		/* ISA (use ne2k-pci for PCI cards) */
+#if defined(CONFIG_NE2000) || defined(CONFIG_NE2K_CBUS)	/* ISA & PC-9800 CBUS (use ne2k-pci for PCI cards) */
 	{ne_probe, 0},
 #endif
 #ifdef CONFIG_LANCE		/* ISA/VLB (use pcnet32 for PCI cards) */
diff -urN linux-2.5.65-bk1/drivers/net/apne.c linux-2.5.65-bk2/drivers/net/apne.c
--- linux-2.5.65-bk1/drivers/net/apne.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/drivers/net/apne.c	Mon Mar 31 12:39:50 2003
@@ -111,9 +111,6 @@
 #define MANUAL_HWADDR5 0x9a
 */
 
-#define WORDSWAP(a) ( (((a)>>8)&0xff) | ((a)<<8) )
-
-
 static const char version[] =
     "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
 
@@ -402,10 +399,9 @@
     }
 
     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
-
-    hdr->count = WORDSWAP(hdr->count);
-
     ei_status.dmaing &= ~0x01;
+
+    le16_to_cpus(&hdr->count);
 }
 
 /* Block input and output, similar to the Crynwr packet driver.  If you
diff -urN linux-2.5.65-bk1/drivers/net/at1700.c linux-2.5.65-bk2/drivers/net/at1700.c
--- linux-2.5.65-bk1/drivers/net/at1700.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/drivers/net/at1700.c	Mon Mar 31 12:39:50 2003
@@ -34,6 +34,10 @@
 	only is it difficult to detect, it also moves around in I/O space in
 	response to inb()s from other device probes!
 */
+/*
+	99/03/03  Allied Telesis RE1000 Plus support by T.Hagawa
+	99/12/30	port to 2.3.35 by K.Takai
+*/
 
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -76,10 +80,17 @@
  *	ISA
  */
 
+#ifndef CONFIG_X86_PC9800
 static int at1700_probe_list[] __initdata = {
 	0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
 };
 
+#else /* CONFIG_X86_PC9800 */
+static int at1700_probe_list[] __initdata = {
+	0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0
+};
+
+#endif /* CONFIG_X86_PC9800 */
 /*
  *	MCA
  */
@@ -122,6 +133,7 @@
 
 
 /* Offsets from the base address. */
+#ifndef CONFIG_X86_PC9800
 #define STATUS			0
 #define TX_STATUS		0
 #define RX_STATUS		1
@@ -136,6 +148,7 @@
 #define TX_START		10
 #define COL16CNTL		11		/* Controll Reg for 16 collisions */
 #define MODE13			13
+#define RX_CTRL			14
 /* Configuration registers only on the '865A/B chips. */
 #define EEPROM_Ctrl 	16
 #define EEPROM_Data 	17
@@ -144,8 +157,39 @@
 #define IOCONFIG		18		/* Either read the jumper, or move the I/O. */
 #define IOCONFIG1		19
 #define	SAPROM			20		/* The station address PROM, if no EEPROM. */
+#define MODE24			24
 #define RESET			31		/* Write to reset some parts of the chip. */
 #define AT1700_IO_EXTENT	32
+#define PORT_OFFSET(o) (o)
+#else /* CONFIG_X86_PC9800 */
+#define STATUS			(0x0000)
+#define TX_STATUS		(0x0000)
+#define RX_STATUS		(0x0001)
+#define TX_INTR			(0x0200)/* Bit-mapped interrupt enable registers. */
+#define RX_INTR			(0x0201)
+#define TX_MODE			(0x0400)
+#define RX_MODE			(0x0401)
+#define CONFIG_0		(0x0600)/* Misc. configuration settings. */
+#define CONFIG_1		(0x0601)
+/* Run-time register bank 2 definitions. */
+#define DATAPORT		(0x0800)/* Word-wide DMA or programmed-I/O dataport. */
+#define TX_START		(0x0a00)
+#define COL16CNTL		(0x0a01)/* Controll Reg for 16 collisions */
+#define MODE13			(0x0c01)
+#define RX_CTRL			(0x0e00)
+/* Configuration registers only on the '865A/B chips. */
+#define EEPROM_Ctrl 	(0x1000)
+#define EEPROM_Data 	(0x1200)
+#define CARDSTATUS	16			/* FMV-18x Card Status */
+#define CARDSTATUS1	17			/* FMV-18x Card Status */
+#define IOCONFIG		(0x1400)/* Either read the jumper, or move the I/O. */
+#define IOCONFIG1		(0x1600)
+#define	SAPROM			20		/* The station address PROM, if no EEPROM. */
+#define	MODE24			(0x1800)/* The station address PROM, if no EEPROM. */
+#define RESET			(0x1e01)/* Write to reset some parts of the chip. */
+#define PORT_OFFSET(o) ({ int _o_ = (o); (_o_ & ~1) * 0x100 + (_o_ & 1); })
+#endif /* CONFIG_X86_PC9800 */
+
 
 #define TX_TIMEOUT		10
 
@@ -225,8 +269,20 @@
 	int slot, ret = -ENODEV;
 	struct net_local *lp;
 	
+#ifndef CONFIG_X86_PC9800
 	if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name))
 		return -EBUSY;
+#else
+	for (i = 0; i < 0x2000; i += 0x0200) {
+		if (!request_region(ioaddr + i, 2, dev->name)) {
+			while (i > 0) {
+				i -= 0x0200;
+				release_region(ioaddr + i, 2);
+			}
+			return -EBUSY;
+		}
+	}
+#endif
 
 		/* Resetting the chip doesn't reset the ISA interface, so don't bother.
 	   That means we have to be careful with the register values we probe for.
@@ -317,10 +373,17 @@
 		/* Reset the internal state machines. */
 	outb(0, ioaddr + RESET);
 
-	if (is_at1700)
+	if (is_at1700) {
+#ifndef CONFIG_X86_PC9800
 		irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
 						   | (read_eeprom(ioaddr, 0)>>14)];
-	else {
+#else
+		{
+			char re1000plus_irqmap[4] = {3, 5, 6, 12};
+			irq = re1000plus_irqmap[inb(ioaddr + IOCONFIG1) >> 6];
+		}
+#endif
+	} else {
 		/* Check PnP mode for FMV-183/184/183A/184A. */
 		/* This PnP routine is very poor. IO and IRQ should be known. */
 		if (inb(ioaddr + CARDSTATUS1) & 0x20) {
@@ -392,18 +455,22 @@
 	/* Set the station address in bank zero. */
 	outb(0x00, ioaddr + CONFIG_1);
 	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + 8 + i);
+		outb(dev->dev_addr[i], ioaddr + PORT_OFFSET(8 + i));
 
 	/* Switch to bank 1 and set the multicast table to accept none. */
 	outb(0x04, ioaddr + CONFIG_1);
 	for (i = 0; i < 8; i++)
-		outb(0x00, ioaddr + 8 + i);
+		outb(0x00, ioaddr + PORT_OFFSET(8 + i));
 
 
 	/* Switch to bank 2 */
 	/* Lock our I/O address, and set manual processing mode for 16 collisions. */
 	outb(0x08, ioaddr + CONFIG_1);
+#ifndef CONFIG_X86_PC9800
 	outb(dev->if_port, ioaddr + MODE13);
+#else
+	outb(0, ioaddr + MODE13);
+#endif
 	outb(0x00, ioaddr + COL16CNTL);
 
 	if (net_debug)
@@ -447,7 +514,12 @@
 	kfree(dev->priv);
 	dev->priv = NULL;
 err_out:
+#ifndef CONFIG_X86_PC9800
 	release_region(ioaddr, AT1700_IO_EXTENT);
+#else
+	for (i = 0; i < 0x2000; i += 0x0200)
+		release_region(ioaddr + i, 2);
+#endif
 	return ret;
 }
 
@@ -459,7 +531,11 @@
 #define EE_DATA_READ	0x80	/* EEPROM chip data out, in reg. 17. */
 
 /* Delay between EEPROM clock transitions. */
+#ifndef CONFIG_X86_PC9800
 #define eeprom_delay()	do { } while (0)
+#else
+#define eeprom_delay()	__asm__ ("out%B0 %%al,%0" :: "N"(0x5f))
+#endif
 
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD	(5 << 6)
@@ -542,12 +618,12 @@
 		inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80
 		? "IRQ conflict" : "network cable problem");
 	printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
-	 dev->name, inw (ioaddr + 0), inw (ioaddr + 2), inw (ioaddr + 4),
-		inw (ioaddr + 6), inw (ioaddr + 8), inw (ioaddr + 10),
-		inw (ioaddr + 12), inw (ioaddr + 14));
+	 dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
+		inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
+		inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
 	lp->stats.tx_errors++;
 	/* ToDo: We should try to restart the adaptor... */
-	outw (0xffff, ioaddr + 24);
+	outw(0xffff, ioaddr + MODE24);
 	outw (0xffff, ioaddr + TX_STATUS);
 	outb (0x5a, ioaddr + CONFIG_0);
 	outb (0xe8, ioaddr + CONFIG_1);
@@ -704,7 +780,7 @@
 				   dev->name, inb(ioaddr + RX_MODE), status);
 #ifndef final_version
 		if (status == 0) {
-			outb(0x05, ioaddr + 14);
+			outb(0x05, ioaddr + RX_CTRL);
 			break;
 		}
 #endif
@@ -724,7 +800,7 @@
 					   dev->name, pkt_len);
 				/* Prime the FIFO and then flush the packet. */
 				inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
-				outb(0x05, ioaddr + 14);
+				outb(0x05, ioaddr + RX_CTRL);
 				lp->stats.rx_errors++;
 				break;
 			}
@@ -734,7 +810,7 @@
 					   dev->name, pkt_len);
 				/* Prime the FIFO and then flush the packet. */
 				inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
-				outb(0x05, ioaddr + 14);
+				outb(0x05, ioaddr + RX_CTRL);
 				lp->stats.rx_dropped++;
 				break;
 			}
@@ -761,7 +837,7 @@
 			if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
 				break;
 			inw(ioaddr + DATAPORT);				/* dummy status read */
-			outb(0x05, ioaddr + 14);
+			outb(0x05, ioaddr + RX_CTRL);
 		}
 
 		if (net_debug > 5)
@@ -844,24 +920,28 @@
 		outb(0x02, ioaddr + RX_MODE);	/* Use normal mode. */
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave (&lp->lock, flags);
 	if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
 		int saved_bank = inw(ioaddr + CONFIG_0);
 		/* Switch to bank 1 and set the multicast table. */
 		outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);
 		for (i = 0; i < 8; i++)
-			outb(mc_filter[i], ioaddr + 8 + i);
+			outb(mc_filter[i], ioaddr + PORT_OFFSET(8 + i));
 		memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
 		outw(saved_bank, ioaddr + CONFIG_0);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore (&lp->lock, flags);
 	return;
 }
 
 #ifdef MODULE
 static struct net_device dev_at1700;
+#ifndef CONFIG_X86_PC9800
 static int io = 0x260;
+#else
+static int io = 0xd0;
+#endif
+
 static int irq;
 
 MODULE_PARM(io, "i");
@@ -901,7 +981,15 @@
 
 	/* If we don't do this, we can't re-insmod it later. */
 	free_irq(dev_at1700.irq, NULL);
+#ifndef CONFIG_X86_PC9800
 	release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
+#else
+	{
+		int i;
+		for (i = 0; i < 0x2000; i += 0x200)
+			release_region(dev_at1700.base_addr + i, 2);
+	}
+#endif
 }
 #endif /* MODULE */
 MODULE_LICENSE("GPL");
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100.h linux-2.5.65-bk2/drivers/net/e100/e100.h
--- linux-2.5.65-bk1/drivers/net/e100/e100.h	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100.h	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -57,6 +57,8 @@
 #include <linux/if.h>
 #include <asm/uaccess.h>
 #include <linux/ip.h>
+#include <linux/if_vlan.h>
+#include <linux/mii.h>
 
 #define E100_REGS_LEN 1
 /*
@@ -301,6 +303,9 @@
 
 /* EEPROM bit definitions */
 /*- EEPROM control register bits */
+#define EEPROM_FLAG_ASF  0x8000
+#define EEPROM_FLAG_GCL  0x4000
+
 #define EN_TRNF          0x10	/* Enable turnoff */
 #define EEDO             0x08	/* EEPROM data out */
 #define EEDI             0x04	/* EEPROM data in (set for writing data) */
@@ -319,6 +324,8 @@
 #define EEPROM_COMPATIBILITY_WORD       3
 #define EEPROM_PWA_NO                   8
 #define EEPROM_ID_WORD			0x0A
+#define EEPROM_CONFIG_ASF		0x0D
+#define EEPROM_SMBUS_ADDR		0x90
 
 #define EEPROM_SUM                      0xbaba
 
@@ -358,7 +365,7 @@
 #define CB_STATUS_MASK          BIT_12_15	/* CB Status Mask (4-bits) */
 #define CB_STATUS_COMPLETE      BIT_15	/* CB Complete Bit */
 #define CB_STATUS_OK            BIT_13	/* CB OK Bit */
-#define CB_STATUS_UNDERRUN      BIT_12	/* CB A Bit */
+#define CB_STATUS_VLAN          BIT_12 /* CB Valn detected Bit */
 #define CB_STATUS_FAIL          BIT_11	/* CB Fail (F) Bit */
 
 /*misc command bits */
@@ -851,6 +858,7 @@
 };
 
 struct e100_private {
+	struct vlan_group *vlgrp;
 	u32 flags;		/* board management flags */
 	u32 tx_per_underrun;	/* number of good tx frames per underrun */
 	unsigned int tx_count;	/* count of tx frames, so we can request an interrupt */
@@ -886,7 +894,6 @@
 	struct driver_stats drv_stats;
 
 	u8 rev_id;		/* adapter PCI revision ID */
-	unsigned long device_type;	/* device type from e100_vendor.h */
 
 	unsigned int phy_addr;	/* address of PHY component */
 	unsigned int PhyId;	/* ID of PHY component */
@@ -923,8 +930,6 @@
 
 	struct cfg_params params;	/* adapter's command line parameters */
 
-	char *id_string;
-
 	u32 speed_duplex_caps;	/* adapter's speed/duplex capabilities */
 
 	/* WOL params for ethtool */
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_config.c linux-2.5.65-bk2/drivers/net/e100/e100_config.c
--- linux-2.5.65-bk1/drivers/net/e100/e100_config.c	Mon Mar 17 13:44:02 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_config.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -521,6 +521,25 @@
 	spin_unlock_bh(&(bdp->config_lock));
 }
 
+void
+e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable)
+{
+	spin_lock_bh(&(bdp->config_lock));
+	if (enable) {
+		if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) {
+			bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE;
+			E100_CONFIG(bdp, 22);
+		}
+
+	} else {
+		if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) {
+			bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE;
+			E100_CONFIG(bdp, 22);
+		}
+	}
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
 /**
  * e100_config_loopback_mode
  * @bdp: atapter's private data struct
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_config.h linux-2.5.65-bk2/drivers/net/e100/e100_config.h
--- linux-2.5.65-bk1/drivers/net/e100/e100_config.h	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_config.h	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -163,5 +163,5 @@
 extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode);
 extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable);
 extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable);
-
+extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable);
 #endif /* _E100_CONFIG_INC_ */
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_eeprom.c linux-2.5.65-bk2/drivers/net/e100/e100_eeprom.c
--- linux-2.5.65-bk1/drivers/net/e100/e100_eeprom.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_eeprom.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_main.c linux-2.5.65-bk2/drivers/net/e100/e100_main.c
--- linux-2.5.65-bk1/drivers/net/e100/e100_main.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_main.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -45,8 +45,22 @@
 **********************************************************************/
 
 /* Change Log
- *
- * 2.1.29	12/20/02
+ * 
+ * 2.2.21	02/11/03
+ * o Removed marketing brand strings. Instead, Using generic string 
+ *   "Intel(R) PRO/100 Network Connection" for all adapters.
+ * o Implemented ethtool -S option
+ * o Strip /proc/net/PRO_LAN_Adapters files for kernel driver
+ * o Bug fix: Read wrong byte in EEPROM when offset is odd number
+ * o Bug fix: PHY loopback test fails on ICH devices
+ * o Bug fix: System panic on e100_close when repeating Hot Remove and 
+ *   Add in a team
+ * o Bug fix: Linux Bonding driver claims adapter's link loss because of
+ *   not updating last_rx field
+ * o Bug fix: e100 does not check validity of MAC address
+ * o New feature: added ICH5 support
+ * 
+ * 2.1.27	11/20/02
  *   o Bug fix: Device command timeout due to SMBus processing during init
  *   o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly
  *   o Bug fix: Not using EEPROM WoL setting as default in ethtool
@@ -62,15 +76,6 @@
  *     ifconfig down, rmmod and insmod
  *
  * 2.1.24       10/7/02
- *   o Bug fix: Wrong files under /proc/net/PRO_LAN_Adapters/ when interface
- *     name is changed
- *   o Bug fix: Rx skb corruption when Rx polling code and Rx interrupt code
- *     are executing during stress traffic at shared interrupt system. 
- *     Removed Rx polling code
- *   o Added detailed printk if selftest failed when insmod
- *   o Removed misleading printks
- *
- * 2.1.12       8/2/02
  */
  
 #include <linux/config.h>
@@ -81,7 +86,8 @@
 #include "e100_ucode.h"
 #include "e100_config.h"
 #include "e100_phy.h"
-#include "e100_vendor.h"
+
+extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp);
 
 static char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
 	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
@@ -127,7 +133,6 @@
 
 static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
 
-#include <linux/mii.h>
 static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);
 
 static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
@@ -136,11 +141,15 @@
 static void e100_non_tx_background(unsigned long);
 
 /* Global Data structures and variables */
-char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.29-k4";
+char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation";
+char e100_driver_version[]="2.2.21-k1";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
+static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group
+		*grp);
+static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
+static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
 
 #ifdef CONFIG_PM
 static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
@@ -186,7 +195,6 @@
 static void e100_set_multi(struct net_device *);
 void e100_set_speed_duplex(struct e100_private *);
 
-char *e100_get_brand_msg(struct e100_private *);
 static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
 static u8 e100_sw_init(struct e100_private *);
 static void e100_tco_workaround(struct e100_private *);
@@ -220,6 +228,7 @@
 				 char *);
 unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
 void e100_exec_cmplx(struct e100_private *, u32, u8);
+static unsigned char e100_asf_enabled(struct e100_private *bdp);
 
 /**
  * e100_get_rx_struct - retrieve cell to hold skb buff from the pool
@@ -607,7 +616,9 @@
 	}
 
 	if (((bdp->pdev->device > 0x1030)
-	     && (bdp->pdev->device < 0x103F))
+	       && (bdp->pdev->device < 0x103F))
+	    || ((bdp->pdev->device >= 0x1050)
+	       && (bdp->pdev->device <= 0x1057))
 	    || (bdp->pdev->device == 0x2449)
 	    || (bdp->pdev->device == 0x2459)
 	    || (bdp->pdev->device == 0x245D)) {
@@ -646,6 +657,9 @@
                 goto err_pci;
 	}
 	
+	dev->vlan_rx_register = e100_vlan_rx_register;
+	dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
 	dev->irq = pcid->irq;
 	dev->open = &e100_open;
 	dev->hard_start_xmit = &e100_xmit_frame;
@@ -655,9 +669,11 @@
 	dev->set_multicast_list = &e100_set_multi;
 	dev->set_mac_address = &e100_set_mac;
 	dev->do_ioctl = &e100_ioctl;
-	if (bdp->flags & USE_IPCB) {
-		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
-	}
+
+	if (bdp->flags & USE_IPCB)
+	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
+			NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+		
 	e100nics++;
 
 	e100_get_speed_duplex_caps(bdp);
@@ -668,25 +684,24 @@
         memcpy(bdp->ifname, dev->name, IFNAMSIZ);
         bdp->ifname[IFNAMSIZ-1] = 0;	
 
-	bdp->device_type = ent->driver_data;
 	printk(KERN_NOTICE
 	       "e100: %s: %s\n", 
-	       bdp->device->name, e100_get_brand_msg(bdp));
+	       bdp->device->name, "Intel(R) PRO/100 Network Connection");
 	e100_print_brd_conf(bdp);
-	bdp->id_string = e100_get_brand_msg(bdp);
 
 	bdp->wolsupported = 0;
 	bdp->wolopts = 0;
 	
 	/* Check if WoL is enabled on EEPROM */
 	if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) {
+		/* Magic Packet WoL is enabled on device by default */
+		/* if EEPROM WoL bit is TRUE                        */
+		bdp->wolsupported = WAKE_MAGIC;
+		bdp->wolopts = WAKE_MAGIC;
 		if (bdp->rev_id >= D101A4_REV_ID)
 			bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
 		if (bdp->rev_id >= D101MA_REV_ID)
 			bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
-		/* Magic Packet WoL is enabled on device by default */
-		/* if EEPROM WoL bit is TRUE                        */
-		bdp->wolopts = WAKE_MAGIC;
 	}
 
 	printk(KERN_NOTICE "\n");
@@ -752,6 +767,34 @@
 	--e100nics;
 }
 
+static struct pci_device_id e100_id_table[] __devinitdata = {
+	{0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+  	{0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },	
+	{0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
+	{0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
+	{0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
+	{0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0,} /* This has to be the last entry*/
+};
 MODULE_DEVICE_TABLE(pci, e100_id_table);
 
 static struct pci_driver e100_driver = {
@@ -994,13 +1037,14 @@
 {
 	struct e100_private *bdp = dev->priv;
 
+	e100_disable_clear_intr(bdp);
+	free_irq(dev->irq, dev);
 	bdp->intr_mask = SCB_INT_MASK;
 	e100_isolate_driver(bdp);
 
 	netif_carrier_off(bdp->device);
 	bdp->cur_line_speed = 0;
 	bdp->cur_dplx_mode = 0;
-	free_irq(dev->irq, dev);
 	e100_clear_pools(bdp);
 
 	return 0;
@@ -1097,6 +1141,8 @@
 	int rc = -1;
 	struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
 
+	if (!is_valid_ether_addr(p_sockaddr->sa_data))
+		return -EADDRNOTAVAIL;
 	bdp = dev->priv;
 
 	if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
@@ -1231,6 +1277,10 @@
 
 	/* read the MAC address from the eprom */
 	e100_rd_eaddr(bdp);
+	if (!is_valid_ether_addr(bdp->device->dev_addr)) {
+		printk(KERN_ERR "e100: Invalid Ethernet address\n");
+		return false;
+	}
 	/* read NIC's part number */
 	e100_rd_pwa_no(bdp);
 
@@ -1670,6 +1720,11 @@
 	} else {
 		if (netif_running(dev))
 			netif_stop_queue(dev);
+		/* When changing to non-autoneg, device may lose  */
+		/* link with some switches. e100 will try to      */
+		/* revover link by sending command to PHY layer   */
+		if (bdp->params.e100_speed_duplex != E100_AUTONEG)
+			e100_force_speed_duplex_to_phy(bdp);
 	}
 
 	rmb();
@@ -1793,7 +1848,8 @@
 	bdp = dev->priv;
 
 	intr_status = readw(&bdp->scb->scb_status);
-	if (!intr_status || (intr_status == 0xffff)) {
+	/* If not my interrupt, just return */
+	if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) {
 		return;
 	}
 
@@ -1993,17 +2049,15 @@
 		} else {
 			skb->ip_summed = CHECKSUM_NONE;
 		}
-		switch (netif_rx(skb)) {
-		case NET_RX_BAD:
-		case NET_RX_DROP:
-		case NET_RX_CN_MOD:
-		case NET_RX_CN_HIGH:
-			break;
-		default:
-			bdp->drv_stats.net_stats.rx_bytes += skb->len;
-			break;
-		}
 
+		if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) {
+			vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid));
+		} else {
+			netif_rx(skb);
+		}
+		dev->last_rx = jiffies;
+		bdp->drv_stats.net_stats.rx_bytes += skb->len;
+		
 		rfd_cnt++;
 	}			/* end of rfd loop */
 
@@ -2096,6 +2150,11 @@
 		tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE;
 	}
 
+	if(bdp->vlgrp && vlan_tx_tag_present(skb)) {
+		(tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE;
+		(tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb));
+	}
+	
 	tcb->tcb_hdr.cb_status = 0;
 	tcb->tcb_thrshld = bdp->tx_thld;
 	tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
@@ -2114,7 +2173,8 @@
 
 		if ((ip->protocol == IPPROTO_TCP) ||
 		    (ip->protocol == IPPROTO_UDP)) {
-			tcb->tcbu.ipcb.ip_activation_high =
+
+			tcb->tcbu.ipcb.ip_activation_high |=
 				IPCB_HARDWAREPARSING_ENABLE;
 			tcb->tcbu.ipcb.ip_schedule |=
 				IPCB_TCPUDP_CHECKSUM_ENABLE;
@@ -2682,13 +2742,12 @@
 		udelay(20);
 	}
 
-	/* Mask off our interrupt line -- its unmasked after reset */
+	/* Mask off our interrupt line -- it is unmasked after reset */
 	e100_disable_clear_intr(bdp);
 #ifdef E100_CU_DEBUG	
 	bdp->last_cmd = 0;
 	bdp->last_sub_cmd = 0;
 #endif	
-
 }
 
 /**
@@ -2901,27 +2960,6 @@
 }
 
 /**
- * e100_get_brand_msg
- * @bdp: atapter's private data struct
- *
- * This routine checks if there is specified branding message for a given board
- * type and returns a pointer to the string containing the branding message.
- */
-char *
-e100_get_brand_msg(struct e100_private *bdp)
-{
-	int i;
-
-	for (i = 0; e100_vendor_info_array[i].idstr != NULL; i++) {
-		if (e100_vendor_info_array[i].device_type == bdp->device_type) {
-			return e100_vendor_info_array[i].idstr;
-		}
-	}
-
-	return e100_vendor_info_array[E100_ALL_BOARDS].idstr;
-}
-
-/**
  * e100_pci_setup - setup the adapter's PCI information
  * @pcid: adapter's pci_dev struct
  * @bdp: atapter's private data struct
@@ -3004,12 +3042,17 @@
 void
 e100_set_speed_duplex(struct e100_private *bdp)
 {
-	if (netif_carrier_ok(bdp->device))
+	int carrier_ok;
+	/* Device may lose link with some siwtches when */
+	/* changing speed/duplex to non-autoneg. e100   */
+	/* needs to remember carrier state in order to  */
+	/* start watchdog timer for recovering link     */
+	if ((carrier_ok = netif_carrier_ok(bdp->device)))
 		e100_isolate_driver(bdp);
 	e100_phy_set_speed_duplex(bdp, true);
 	e100_config_fc(bdp);	/* re-config flow-control if necessary */
 	e100_config(bdp);	
-	if (netif_carrier_ok(bdp->device))
+	if (carrier_ok)
 		e100_deisolate_driver(bdp, false);
 }
 
@@ -3426,6 +3469,7 @@
 	u16 first_word, last_word;
 	int i, max_len;
 	void *ptr;
+	u8 *eeprom_data_bytes = (u8 *)eeprom_data;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -3461,7 +3505,9 @@
 		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
 			return -EFAULT;
 
-		if (copy_to_user(usr_eeprom_ptr, eeprom_data, ecmd.len))
+		if(ecmd.offset & 1)
+			eeprom_data_bytes++;
+		if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len))
 			return -EFAULT;
 	} else {
 		if (ecmd.magic != E100_EEPROM_MAGIC)
@@ -3754,7 +3800,8 @@
 		return -EFAULT;
 
 	switch (info.string_set) {
-	case ETH_SS_TEST:
+	case ETH_SS_TEST: {
+		int ret = 0;
 		if (info.len > E100_MAX_TEST_RES)
 			info.len = E100_MAX_TEST_RES;
 		strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
@@ -3766,7 +3813,13 @@
 			sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
 				test_strings[i]);
 		}
-		break;
+		if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+			ret = -EFAULT;
+		if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
+			ret = -EFAULT;
+		kfree(strings);
+		return ret;
+	}
 	case ETH_SS_STATS: {
 		char *strings = NULL;
 		void *addr = ifr->ifr_data;
@@ -3783,19 +3836,6 @@
 	default:
 		return -EOPNOTSUPP;
 	}
-
-	if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) {
-		kfree(strings);
-		return -EFAULT;
-	}
-
-	if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN)) {
-		kfree(strings);
-		return -EFAULT;
-	}
-
-	kfree(strings);
-	return 0;
 }
 
 static int
@@ -4022,6 +4062,45 @@
 	spin_unlock_bh(&(bdp->bd_non_tx_lock));
 }
 
+static void
+e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+	struct e100_private *bdp = netdev->priv;
+
+	e100_disable_clear_intr(bdp);
+	bdp->vlgrp = grp;
+
+	if(grp) {
+		/* enable VLAN tag insert/strip */
+		e100_config_vlan_drop(bdp, true);
+
+	} else {
+		/* disable VLAN tag insert/strip */
+		e100_config_vlan_drop(bdp, false);
+	}
+
+	e100_config(bdp);
+	e100_set_intr_mask(bdp);
+}
+
+static void
+e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+	/* We don't do Vlan filtering */
+	return;
+}
+
+static void
+e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+	struct e100_private *bdp = netdev->priv;
+
+	if(bdp->vlgrp)
+		bdp->vlgrp->vlan_devices[vid] = NULL;
+	/* We don't do Vlan filtering */
+	return;
+}
+
 #ifdef CONFIG_PM
 static int
 e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
@@ -4057,7 +4136,7 @@
 	e100_do_wol(pcid, bdp);
 	
 	/* If wol is enabled */
-	if (bdp->wolopts) {
+	if (bdp->wolopts || e100_asf_enabled(bdp)) {
 		pci_enable_wake(pcid, 3, 1);	/* Enable PME for power state D3 */
 		pci_set_power_state(pcid, 3);	/* Set power state to D3.        */
 	} else {
@@ -4085,6 +4164,31 @@
 }
 #endif /* CONFIG_PM */
 
+/**
+ * e100_asf_enabled - checks if ASF is configured on the current adaper
+ *                    by reading registers 0xD and 0x90 in the EEPROM 
+ * @bdp: atapter's private data struct
+ *
+ * Returns: true if ASF is enabled
+ */
+static unsigned char
+e100_asf_enabled(struct e100_private *bdp)
+{
+	u16 asf_reg;
+	u16 smbus_addr_reg;
+	if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) {
+		asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF);
+		if ((asf_reg & EEPROM_FLAG_ASF)
+		    && !(asf_reg & EEPROM_FLAG_GCL)) {
+			smbus_addr_reg = 
+				e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR);
+			if ((smbus_addr_reg & 0xFF) != 0xFE) 
+				return true;
+		}
+	}
+	return false;
+}
+
 #ifdef E100_CU_DEBUG
 unsigned char
 e100_cu_unknown_state(struct e100_private *bdp)
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_phy.c linux-2.5.65-bk2/drivers/net/e100/e100_phy.c
--- linux-2.5.65-bk1/drivers/net/e100/e100_phy.c	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_phy.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -636,7 +636,6 @@
 	control &= ~BMCR_ANENABLE;
 	control &= ~BMCR_LOOPBACK;
 
-	/* Check e100.c values */
 	switch (bdp->params.e100_speed_duplex) {
 	case E100_SPEED_10_HALF:
 		control &= ~BMCR_SPEED100;
@@ -682,6 +681,41 @@
 	} while (true);
 }
 
+void
+e100_force_speed_duplex_to_phy(struct e100_private *bdp)
+{
+	u16 control;
+
+	e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
+	control &= ~BMCR_ANENABLE;
+	control &= ~BMCR_LOOPBACK;
+
+	switch (bdp->params.e100_speed_duplex) {
+	case E100_SPEED_10_HALF:
+		control &= ~BMCR_SPEED100;
+		control &= ~BMCR_FULLDPLX;
+		break;
+
+	case E100_SPEED_10_FULL:
+		control &= ~BMCR_SPEED100;
+		control |= BMCR_FULLDPLX;
+		break;
+
+	case E100_SPEED_100_HALF:
+		control |= BMCR_SPEED100;
+		control &= ~BMCR_FULLDPLX;
+		break;
+
+	case E100_SPEED_100_FULL:
+		control |= BMCR_SPEED100;
+		control |= BMCR_FULLDPLX;
+		break;
+	}
+
+	/* Send speed/duplex command to PHY layer. */
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
+}
+
 /* 
  * Procedure: e100_set_fc
  *
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_phy.h linux-2.5.65-bk2/drivers/net/e100/e100_phy.h
--- linux-2.5.65-bk1/drivers/net/e100/e100_phy.h	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_phy.h	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -30,8 +30,6 @@
 
 #include "e100.h"
 
-#include <linux/mii.h>
-
 /*
  * Auto-polarity enable/disable
  * e100_autopolarity = 0 => disable auto-polarity
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_test.c linux-2.5.65-bk2/drivers/net/e100/e100_test.c
--- linux-2.5.65-bk1/drivers/net/e100/e100_test.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_test.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -242,6 +242,9 @@
 		 *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
 
 	if (set_loopback) {
+		/* ICH PHY loopback is broken */
+		if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK)
+			loopback_mode = MAC_LOOPBACK;
 		/* Configure loopback on MAC */
 		e100_config_loopback_mode(bdp,loopback_mode);
 	} else {
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_ucode.h linux-2.5.65-bk2/drivers/net/e100/e100_ucode.h
--- linux-2.5.65-bk1/drivers/net/e100/e100_ucode.h	Mon Mar 17 13:44:45 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_ucode.h	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
diff -urN linux-2.5.65-bk1/drivers/net/e100/e100_vendor.h linux-2.5.65-bk2/drivers/net/e100/e100_vendor.h
--- linux-2.5.65-bk1/drivers/net/e100/e100_vendor.h	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/drivers/net/e100/e100_vendor.h	Wed Dec 31 16:00:00 1969
@@ -1,311 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
-  
-  This program is free software; you can redistribute it and/or modify it 
-  under the terms of the GNU General Public License as published by the Free 
-  Software Foundation; either version 2 of the License, or (at your option) 
-  any later version.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-#ifndef E100_VENDOR_ID_INFO
-#define E100_VENDOR_ID_INFO
-/* ====================================================================== */
-/*                              vendor_info                               */
-/* ====================================================================== */
-
-struct e100_vendor_info {
-	unsigned long device_type;
-	char *idstr;
-};
-
-enum e100_device_type {
-	E100_BRD_100TX = 1,
-	E100_BRD_100T4,
-	E100_BRD_10T,
-	E100_BRD_100WFM,
-	E100_BRD_82557,
-	E100_BRD_82557_WOL,
-	E100_BRD_82558,
-	E100_BRD_82558_WOL,
-	E100_BRD_100,
-	E100_BRD_100M,
-	E100_BRD_AOL2,
-	E100_BRD_AOL,
-	E100_PROS_M,
-	E100_PROS_AM,
-	E100_PROS_AM_AOL,
-	E100_PROS_DT,
-	E100_PRO_DT,
-	E100_PROM_DT,
-	E100_PRO_SRV,
-	E100_PRO_SRVP,
-	E100_PROS_SRV,
-	E100_PRO_DUAL,
-	E100_PROS_DUAL,
-	E100_PROP_DUAL,
-	E100_PROP_WOL,
-	E100_PROS_MOB,
-	E100_PRO_CB,
-	E100_PRO_CB_M,
-	E100_PROSR_MOB,
-	E100_PROS_MC,
-	E100_PROSR_MC,
-	E100_PROP_MC,
-	E100_PROSP_MC,
-	E100_PROP_MOB,
-	E100_PROSP_MOB,
-	E100_PRO_MINI,
-	E100_PRO_NET,
-	E100_PROS_NET,
-	E100_PROVM_NET,
-	E100_PROVE_D,
-	E100_82559_LOM,
-	E100_82559_LOM_AOL,
-	E100_82559_LOM_AOL2,
-	E100_82559_LOM_DELL,
-	E100_IBM_MDS,
-	E100_CMPQ_S,
-	E100_PROVE_DA,
-	E100_PROVM_DA,
-	E100_PROVE_LOM,
-	E100_PROVE_NET,
-	E100_82562,
-	E100_82551QM,
-	E100_ALL_BOARDS
-};
-
-struct e100_vendor_info e100_vendor_info_array[] = {
-	{ E100_BRD_100TX, "Intel(R) PRO/100B PCI Adapter (TX)"},
-	{ E100_BRD_100T4, "Intel(R) PRO/100B PCI Adapter (T4)"},
-	{ E100_BRD_10T, "Intel(R) PRO/10+ PCI Adapter"},
-	{ E100_BRD_100WFM, "Intel(R) PRO/100 WfM PCI Adapter"},
-	{ E100_BRD_82557, "Intel(R) 82557-based Integrated Ethernet PCI (10/100)"},
-	{ E100_BRD_82557_WOL, "Intel(R) 82557-based Integrated Ethernet with Wake on LAN*"},
-	{ E100_BRD_82558, "Intel(R) 82558-based Integrated Ethernet"},
-	{ E100_BRD_82558_WOL, "Intel(R) 82558-based Integrated Ethernet with Wake on LAN*"},
-	{ E100_BRD_100, "Intel(R) PRO/100+ PCI Adapter"},
-	{ E100_BRD_100M, "Intel(R) PRO/100+ Management Adapter"},
-	{ E100_BRD_AOL2, "Intel(R) PRO/100+ Alert on LAN* 2 Management Adapter"},
-	{ E100_82559_LOM_DELL, "Intel(R) 8255x Based Network Connection"},
-	{ E100_BRD_AOL, "Intel(R) PRO/100+ Alert on LAN* Management Adapter"},
-	{ E100_PROS_M, "Intel(R) PRO/100 S Management Adapter"},
-	{ E100_PROS_AM, "Intel(R) PRO/100 S Advanced Management Adapter"},
-	{ E100_PROS_AM_AOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* GC"},
-	{ E100_PROS_DT, "Intel(R) PRO/100 S Desktop Adapter"},
-	{ E100_PRO_DT, "Intel(R) PRO/100 Desktop Adapter"},
-	{ E100_PROM_DT, "Intel(R) PRO/100 M Desktop Adapter"},
-	{ E100_PRO_SRV, "Intel(R) PRO/100+ Server Adapter"},
-	{ E100_PRO_SRVP, "Intel(R) PRO/100+ Server Adapter (PILA8470B)"},
-	{ E100_PROS_SRV, "Intel(R) PRO/100 S Server Adapter"},
-	{ E100_PRO_DUAL, "Intel(R) PRO/100 Dual Port Server Adapter"},
-	{ E100_PROS_DUAL, "Intel(R) PRO/100 S Dual Port Server Adapter"},
-	{ E100_PROP_DUAL, "Intel(R) PRO/100+ Dual Port Server Adapter"},
-	{ E100_PROP_WOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* G Server"},
-	{ E100_PROS_MOB, "Intel(R) PRO/100 S Mobile Adapter"},
-	{ E100_PRO_CB, "Intel(R) PRO/100 CardBus II"},
-	{ E100_PRO_CB_M, "Intel(R) PRO/100 LAN+Modem56 CardBus II"},
-	{ E100_PROSR_MOB, "Intel(R) PRO/100 SR Mobile Adapter"},
-	{ E100_PROS_MC, "Intel(R) PRO/100 S Mobile Combo Adapter"},
-	{ E100_PROSR_MC, "Intel(R) PRO/100 SR Mobile Combo Adapter"},
-	{ E100_PROP_MC, "Intel(R) PRO/100 P Mobile Combo Adapter"},
-	{ E100_PROSP_MC, "Intel(R) PRO/100 SP Mobile Combo Adapter"},
-	{ E100_PROP_MOB, "Intel(R) PRO/100 P Mobile Adapter"},
-	{ E100_PROSP_MOB, "Intel(R) PRO/100 SP Mobile Adapter"},
-	{ E100_PRO_MINI, "Intel(R) PRO/100+ Mini PCI"},
-	{ E100_PRO_NET, "Intel(R) PRO/100 Network Connection" },
-	{ E100_PROS_NET, "Intel(R) PRO/100 S Network Connection" },
-	{ E100_PROVM_NET, "Intel(R) PRO/100 VM Network Connection"},
-	{ E100_PROVE_D, "Intel(R) PRO/100 VE Desktop Connection"},
-	{ E100_82559_LOM, "Intel(R) 82559 Fast Ethernet LAN on Motherboard"},
-	{ E100_82559_LOM_AOL, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN*" },
-	{ E100_82559_LOM_AOL2, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN* 2" },
-	{ E100_IBM_MDS, "IBM Mobile, Desktop & Server Adapters"},
-	{ E100_CMPQ_S, "Compaq Fast Ethernet Server Adapter" },
-	{ E100_PROVE_DA, "Intel(R) PRO/100 VE Desktop Adapter"},
-	{ E100_PROVM_DA, "Intel(R) PRO/100 VM Desktop Adapter"},
-	{ E100_PROVE_LOM, "Intel(R) PRO/100 VE Network ConnectionPLC LOM" },
-	{ E100_PROVE_NET, "Intel(R) PRO/100 VE Network Connection"},
-	{ E100_82562, "Intel(R)82562 based Fast Ethernet Connection"},
-	{ E100_82551QM, "Intel(R) PRO/100 M Mobile Connection"},
-	{ E100_ALL_BOARDS, "Intel(R) 8255x-based Ethernet Adapter"},
-	{0,NULL}
-};
-
-static struct pci_device_id e100_id_table[] __devinitdata = {
-	{0x8086, 0x1229, 0x8086, 0x0001, 0, 0, E100_BRD_100TX},
-	{0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
-	{0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
-	{0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
-	{0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
-	{0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
-	{0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
-	{0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
-	{0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
-	{0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
-	{0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
-	{0x8086, 0x1229, 0x8086, 0x0007, 0, 0, E100_BRD_82558},
-	{0x8086, 0x1229, 0x8086, 0x0008, 0, 0, E100_BRD_82558_WOL},
-	{0x8086, 0x1229, 0x8086, 0x0009, 0, 0, E100_BRD_100},
-	{0x8086, 0x1229, 0x8086, 0x000A, 0, 0, E100_BRD_100M},
-	{0x8086, 0x1229, 0x8086, 0x000B, 0, 0, E100_BRD_100},
-	{0x8086, 0x1229, 0x8086, 0x000C, 0, 0, E100_BRD_100M},
-	{0x8086, 0x1229, 0x8086, 0x000D, 0, 0, E100_BRD_AOL2},
-	{0x8086, 0x1229, 0x8086, 0x000E, 0, 0, E100_BRD_AOL},
-	{0x8086, 0x1229, 0x8086, 0x0010, 0, 0, E100_PROS_M},
-	{0x8086, 0x1229, 0x8086, 0x0011, 0, 0, E100_PROS_M},
-	{0x8086, 0x1229, 0x8086, 0x0012, 0, 0, E100_PROS_AM},
-	{0x8086, 0x1229, 0x8086, 0x0013, 0, 0, E100_PROS_AM},
-	{0x8086, 0x1229, 0x8086, 0x0030, 0, 0, E100_PROS_AM_AOL},
-	{0x8086, 0x1229, 0x8086, 0x0040, 0, 0, E100_PROS_DT},
-	{0x8086, 0x1229, 0x8086, 0x0041, 0, 0, E100_PROS_DT},
-	{0x8086, 0x1229, 0x8086, 0x0042, 0, 0, E100_PRO_DT},
-	{0x8086, 0x1229, 0x8086, 0x0050, 0, 0, E100_PROS_DT},
-	{0x8086, 0x1229, 0x8086, 0x0070, 0, 0, E100_PROM_DT},
-	{0x8086, 0x1229, 0x8086, 0x1009, 0, 0, E100_PRO_SRV},
-	{0x8086, 0x1229, 0x8086, 0x100C, 0, 0, E100_PRO_SRVP},
-	{0x8086, 0x1229, 0x8086, 0x1012, 0, 0, E100_PROS_SRV},
-	{0x8086, 0x1229, 0x8086, 0x1013, 0, 0, E100_PROS_SRV},
-	{0x8086, 0x1229, 0x8086, 0x1014, 0, 0, E100_PRO_DUAL},
-	{0x8086, 0x1229, 0x8086, 0x1015, 0, 0, E100_PROS_DUAL},
-	{0x8086, 0x1229, 0x8086, 0x1016, 0, 0, E100_PROS_DUAL},
-	{0x8086, 0x1229, 0x8086, 0x1017, 0, 0, E100_PROP_DUAL},
-	{0x8086, 0x1229, 0x8086, 0x1030, 0, 0, E100_PROP_WOL},
-	{0x8086, 0x1229, 0x8086, 0x1040, 0, 0, E100_PROS_SRV},
-	{0x8086, 0x1229, 0x8086, 0x1041, 0, 0, E100_PROS_SRV},
-	{0x8086, 0x1229, 0x8086, 0x1042, 0, 0, E100_PRO_SRV},
-	{0x8086, 0x1229, 0x8086, 0x1050, 0, 0, E100_PROS_SRV},
-	{0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, 
-	{0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, 
-	{0x8086, 0x1229, 0x8086, 0x2009, 0, 0, E100_PROS_MOB},
-	{0x8086, 0x1229, 0x8086, 0x200D, 0, 0, E100_PRO_CB},
-	{0x8086, 0x1229, 0x8086, 0x200E, 0, 0, E100_PRO_CB_M},
-	{0x8086, 0x1229, 0x8086, 0x200F, 0, 0, E100_PROSR_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2010, 0, 0, E100_PROS_MC},
-	{0x8086, 0x1229, 0x8086, 0x2013, 0, 0, E100_PROSR_MC},
-	{0x8086, 0x1229, 0x8086, 0x2016, 0, 0, E100_PROS_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2017, 0, 0, E100_PROS_MC},
-	{0x8086, 0x1229, 0x8086, 0x2018, 0, 0, E100_PROSR_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2019, 0, 0, E100_PROSR_MC},
-	{0x8086, 0x1229, 0x8086, 0x2101, 0, 0, E100_PROP_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2102, 0, 0, E100_PROSP_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2103, 0, 0, E100_PROSP_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2104, 0, 0, E100_PROSP_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2105, 0, 0, E100_PROSP_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2106, 0, 0, E100_PROP_MOB},
-	{0x8086, 0x1229, 0x8086, 0x2107, 0, 0, E100_PRO_NET},
-	{0x8086, 0x1229, 0x8086, 0x2108, 0, 0, E100_PRO_NET},
-	{0x8086, 0x1229, 0x8086, 0x2200, 0, 0, E100_PROP_MC},
-	{0x8086, 0x1229, 0x8086, 0x2201, 0, 0, E100_PROP_MC},
-	{0x8086, 0x1229, 0x8086, 0x2202, 0, 0, E100_PROSP_MC},
-	{0x8086, 0x1229, 0x8086, 0x2203, 0, 0, E100_PRO_MINI},
-	{0x8086, 0x1229, 0x8086, 0x2204, 0, 0, E100_PRO_MINI},
-	{0x8086, 0x1229, 0x8086, 0x2205, 0, 0, E100_PROSP_MC},
-	{0x8086, 0x1229, 0x8086, 0x2206, 0, 0, E100_PROSP_MC},
-	{0x8086, 0x1229, 0x8086, 0x2207, 0, 0, E100_PROSP_MC},
-	{0x8086, 0x1229, 0x8086, 0x2208, 0, 0, E100_PROP_MC},
-	{0x8086, 0x1229, 0x8086, 0x2408, 0, 0, E100_PRO_MINI},
-	{0x8086, 0x1229, 0x8086, 0x240F, 0, 0, E100_PRO_MINI},
-	{0x8086, 0x1229, 0x8086, 0x2411, 0, 0, E100_PRO_MINI},
-	{0x8086, 0x1229, 0x8086, 0x3400, 0, 0, E100_82559_LOM},
-	{0x8086, 0x1229, 0x8086, 0x3000, 0, 0, E100_82559_LOM},
-	{0x8086, 0x1229, 0x8086, 0x3001, 0, 0, E100_82559_LOM_AOL},
-	{0x8086, 0x1229, 0x8086, 0x3002, 0, 0, E100_82559_LOM_AOL2},
-	{0x8086, 0x1229, 0x8086, 0x3006, 0, 0, E100_PROS_NET},
-	{0x8086, 0x1229, 0x8086, 0x3007, 0, 0, E100_PROS_NET},
-	{0x8086, 0x1229, 0x8086, 0x3008, 0, 0, E100_PRO_NET},
-	{0x8086, 0x1229, 0x8086, 0x3010, 0, 0, E100_PROS_NET},
-	{0x8086, 0x1229, 0x8086, 0x3011, 0, 0, E100_PROS_NET},
-	{0x8086, 0x1229, 0x8086, 0x3012, 0, 0, E100_PRO_NET},
-	{0x8086, 0x1229, 0x1014, 0x005C, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x305C, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x405C, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x605C, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x505C, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x105C, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x805C, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x705C, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x01F1, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x0232, 0, 0, E100_IBM_MDS},   
-	{0x8086, 0x1229, 0x1014, 0x0207, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x1014, 0x023F, 0, 0, E100_PRO_NET},   
-	{0x8086, 0x1229, 0x1014, 0x01BC, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x1014, 0x01CE, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x1014, 0x01DC, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x1014, 0x01EB, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x1014, 0x01EC, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x1014, 0x0202, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x1014, 0x0205, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x1014, 0x0217, 0, 0, E100_PRO_NET},     
-	{0x8086, 0x1229, 0x0E11, 0xB01E, 0, 0, E100_CMPQ_S},         
-	{0x8086, 0x1229, 0x0E11, 0xB02F, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB04A, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB0C6, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB0C7, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB0D7, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB0DD, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB0DE, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB0E1, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB134, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB13C, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB144, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB163, 0, 0, E100_CMPQ_S},     
-	{0x8086, 0x1229, 0x0E11, 0xB164, 0, 0, E100_CMPQ_S},
-	{0x8086, 0x1229, 0x1028, PCI_ANY_ID, 0, 0, E100_82559_LOM_DELL},
-	{0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
-
-	{0x8086, 0x2449, 0x1014, 0x0265, 0, 0, E100_PROVE_D},
-	{0x8086, 0x2449, 0x1014, 0x0267, 0, 0, E100_PROVE_D},
-	{0x8086, 0x2449, 0x1014, 0x026A, 0, 0, E100_PROVE_D},
-	{0x8086, 0x2449, 0x8086, 0x3010, 0, 0, E100_PROVE_DA},
-	{0x8086, 0x2449, 0x8086, 0x3011, 0, 0, E100_PROVM_DA},
-	{0x8086, 0x2449, 0x8086, 0x3013, 0, 0, E100_PROVE_NET},
-	{0x8086, 0x2449, 0x8086, 0x3014, 0, 0, E100_PROVM_NET},
-	{0x8086, 0x2449, 0x8086, 0x3016, 0, 0, E100_PROP_MC},
-	{0x8086, 0x2449, 0x8086, 0x3017, 0, 0, E100_PROP_MOB},
-	{0x8086, 0x2449, 0x8086, 0x3018, 0, 0, E100_PRO_NET},
-	{0x8086, 0x2449, 0x0E11, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
-	{0x8086, 0x2449, 0x1014, PCI_ANY_ID, 0, 0, E100_PROVE_D},	
-	{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
-	
-	{0x8086, 0x1059, 0x1179, 0x0005, 0, 0, E100_82551QM},
-	{0x8086, 0x1059, 0x1033, 0x8191, 0, 0, E100_82551QM},
-	{0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82551QM},
-	
-	{0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
-  	{0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
-	{0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},	
-	{0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, 
-	{0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
-	{0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, 
-	{0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, 
-	{0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
-	{0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
-	{0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
-	{0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
-	{0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
-	{0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
-	{0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
-	{0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
-	{0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
-	{0,} /* This has to be the last entry*/
-};
-
-#endif /* E100_VENDOR_ID_INFO */
diff -urN linux-2.5.65-bk1/drivers/net/e1000/e1000.h linux-2.5.65-bk2/drivers/net/e1000/e1000.h
--- linux-2.5.65-bk1/drivers/net/e1000/e1000.h	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/drivers/net/e1000/e1000.h	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -65,6 +65,7 @@
 #include <linux/reboot.h>
 #include <net/checksum.h>
 #include <linux/workqueue.h>
+#include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 
@@ -95,6 +96,15 @@
 #define E1000_RXBUFFER_8192  8192
 #define E1000_RXBUFFER_16384 16384
 
+/* SmartSpeed delimiters */
+#define E1000_SMARTSPEED_DOWNSHIFT 3
+#define E1000_SMARTSPEED_MAX       15
+
+/* Packet Buffer allocations */
+#define E1000_TX_FIFO_SIZE_SHIFT 0xA
+#define E1000_TX_HEAD_ADDR_SHIFT 7
+#define E1000_PBA_TX_MASK 0xFFFF0000
+
 /* Flow Control High-Watermark: 43464 bytes */
 #define E1000_FC_HIGH_THRESH 0xA9C8
 
@@ -107,10 +117,7 @@
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
 #define E1000_TX_QUEUE_WAKE	16
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define E1000_RX_BUFFER_WRITE	16
-
-#define E1000_JUMBO_PBA      0x00000028
-#define E1000_DEFAULT_PBA    0x00000030
+#define E1000_RX_BUFFER_WRITE	16	/* Must be power of 2 */
 
 #define AUTO_ALL_MODES       0
 #define E1000_EEPROM_APME    4
@@ -145,7 +152,8 @@
 };
 
 #define E1000_DESC_UNUSED(R) \
-((((R)->next_to_clean + (R)->count) - ((R)->next_to_use + 1)) % ((R)->count))
+	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+	(R)->next_to_clean - (R)->next_to_use - 1)
 
 #define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
 #define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
@@ -155,6 +163,7 @@
 /* board specific private data structure */
 
 struct e1000_adapter {
+	struct timer_list tx_fifo_stall_timer;
 	struct timer_list watchdog_timer;
 	struct timer_list phy_info_timer;
 	struct vlan_group *vlgrp;
@@ -163,6 +172,7 @@
 	uint32_t rx_buffer_len;
 	uint32_t part_num;
 	uint32_t wol;
+	uint32_t smartspeed;
 	uint16_t link_speed;
 	uint16_t link_duplex;
 	spinlock_t stats_lock;
@@ -177,7 +187,11 @@
 	uint32_t txd_cmd;
 	uint32_t tx_int_delay;
 	uint32_t tx_abs_int_delay;
-	int max_data_per_txd;
+	uint32_t gotcl;
+	uint32_t tx_fifo_head;
+	uint32_t tx_head_addr;
+	uint32_t tx_fifo_size;
+	atomic_t tx_fifo_stall;
 
 	/* RX */
 	struct e1000_desc_ring rx_ring;
@@ -186,6 +200,10 @@
 	uint32_t rx_int_delay;
 	uint32_t rx_abs_int_delay;
 	boolean_t rx_csum;
+	uint32_t gorcl;
+
+	/* Interrupt Throttle Rate */
+	uint32_t itr;
 
 	/* OS defined structs */
 	struct net_device *netdev;
diff -urN linux-2.5.65-bk1/drivers/net/e1000/e1000_ethtool.c linux-2.5.65-bk2/drivers/net/e1000/e1000_ethtool.c
--- linux-2.5.65-bk1/drivers/net/e1000/e1000_ethtool.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/net/e1000/e1000_ethtool.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -38,6 +38,7 @@
 extern int e1000_up(struct e1000_adapter *adapter);
 extern void e1000_down(struct e1000_adapter *adapter);
 extern void e1000_reset(struct e1000_adapter *adapter);
+extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
 
 static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = {
 	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
@@ -129,30 +130,9 @@
 		hw->autoneg = 1;
 		hw->autoneg_advertised = 0x002F;
 		ecmd->advertising = 0x002F;
-	} else {
-		hw->autoneg = 0;
-		switch(ecmd->speed + ecmd->duplex) {
-		case SPEED_10 + DUPLEX_HALF:
-			hw->forced_speed_duplex = e1000_10_half;
-			break;
-		case SPEED_10 + DUPLEX_FULL:
-			hw->forced_speed_duplex = e1000_10_full;
-			break;
-		case SPEED_100 + DUPLEX_HALF:
-			hw->forced_speed_duplex = e1000_100_half;
-			break;
-		case SPEED_100 + DUPLEX_FULL:
-			hw->forced_speed_duplex = e1000_100_full;
-			break;
-		case SPEED_1000 + DUPLEX_FULL:
-			hw->autoneg = 1;
-			hw->autoneg_advertised = ADVERTISE_1000_FULL;
-			break;
-		case SPEED_1000 + DUPLEX_HALF: /* not supported */
-		default:
+	} else
+		if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
 			return -EINVAL;
-		}
-	}
 
 	/* reset the link */
 
@@ -165,16 +145,6 @@
 	return 0;
 }
 
-static inline int
-e1000_eeprom_size(struct e1000_hw *hw)
-{
-	if((hw->mac_type > e1000_82544) &&
-	   (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE))
-		return 512;
-	else
-		return 128;
-}
-
 static void
 e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
                        struct ethtool_drvinfo *drvinfo)
@@ -186,7 +156,7 @@
 	drvinfo->n_stats = E1000_STATS_LEN;
 #define E1000_REGS_LEN 32
 	drvinfo->regdump_len  = E1000_REGS_LEN * sizeof(uint32_t);
-	drvinfo->eedump_len  = e1000_eeprom_size(&adapter->hw);
+	drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2;
 }
 
 static void
@@ -220,9 +190,8 @@
                       struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	int max_len, first_word, last_word;
+	int first_word, last_word;
 	int ret_val = 0;
-	int i;
 
 	if(eeprom->len == 0) {
 		ret_val = -EINVAL;
@@ -231,22 +200,28 @@
 
 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 
-	max_len = e1000_eeprom_size(hw);
-
 	if(eeprom->offset > eeprom->offset + eeprom->len) {
 		ret_val = -EINVAL;
 		goto geeprom_error;
 	}
 
-	if((eeprom->offset + eeprom->len) > max_len)
-		eeprom->len = (max_len - eeprom->offset);
+	if((eeprom->offset + eeprom->len) > (hw->eeprom.word_size * 2))
+		eeprom->len = ((hw->eeprom.word_size * 2) - eeprom->offset);
 
 	first_word = eeprom->offset >> 1;
 	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
 
-	for(i = 0; i <= (last_word - first_word); i++)
-		e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
-
+	if(hw->eeprom.type == e1000_eeprom_spi)
+		ret_val = e1000_read_eeprom(hw, first_word,
+					    last_word - first_word + 1,
+					    eeprom_buff);
+	else {
+		uint16_t i;
+		for (i = 0; i < last_word - first_word + 1; i++)
+			if((ret_val = e1000_read_eeprom(hw, first_word + i, 1,
+						       &eeprom_buff[i])))
+				break;
+	}
 geeprom_error:
 	return ret_val;
 }
@@ -257,9 +232,8 @@
 {
 	struct e1000_hw *hw = &adapter->hw;
 	uint16_t *eeprom_buff;
-	int max_len, first_word, last_word;
 	void *ptr;
-	int i;
+	int max_len, first_word, last_word, ret_val = 0;
 
 	if(eeprom->len == 0)
 		return -EOPNOTSUPP;
@@ -267,7 +241,7 @@
 	if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
 		return -EFAULT;
 
-	max_len = e1000_eeprom_size(hw);
+	max_len = hw->eeprom.word_size * 2;
 
 	if((eeprom->offset + eeprom->len) > max_len)
 		eeprom->len = (max_len - eeprom->offset);
@@ -283,30 +257,31 @@
 	if(eeprom->offset & 1) {
 		/* need read/modify/write of first changed EEPROM word */
 		/* only the second byte of the word is being modified */
-		e1000_read_eeprom(hw, first_word, &eeprom_buff[0]);
+		ret_val = e1000_read_eeprom(hw, first_word, 1,
+					    &eeprom_buff[0]);
 		ptr++;
 	}
-	if((eeprom->offset + eeprom->len) & 1) {
+	if(((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
 		/* need read/modify/write of last changed EEPROM word */
 		/* only the first byte of the word is being modified */
-		e1000_read_eeprom(hw, last_word,
+		ret_val = e1000_read_eeprom(hw, last_word, 1,
 		                  &eeprom_buff[last_word - first_word]);
 	}
-	if(copy_from_user(ptr, user_data, eeprom->len)) {
-		kfree(eeprom_buff);
-		return -EFAULT;
+	if((ret_val != 0) || copy_from_user(ptr, user_data, eeprom->len)) {
+		ret_val = -EFAULT;
+		goto seeprom_error;
 	}
 
-	for(i = 0; i <= (last_word - first_word); i++)
-		e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]);
+	ret_val = e1000_write_eeprom(hw, first_word,
+				     last_word - first_word + 1, eeprom_buff);
 
 	/* Update the checksum over the first part of the EEPROM if needed */
-	if(first_word <= EEPROM_CHECKSUM_REG)
+	if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG)
 		e1000_update_eeprom_checksum(hw);
 
+seeprom_error:
 	kfree(eeprom_buff);
-
-	return 0;
+	return ret_val;
 }
 
 static void
@@ -333,8 +308,8 @@
 		/* Fall Through */
 
 	default:
-		wol->supported = WAKE_UCAST | WAKE_MCAST
-			         | WAKE_BCAST | WAKE_MAGIC;
+		wol->supported = WAKE_UCAST | WAKE_MCAST |
+				 WAKE_BCAST | WAKE_MAGIC;
 
 		wol->wolopts = 0;
 		if(adapter->wol & E1000_WUFC_EX)
@@ -368,7 +343,7 @@
 		/* Fall Through */
 
 	default:
-		if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY))
+		if(wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
 			return -EOPNOTSUPP;
 
 		adapter->wol = 0;
@@ -542,13 +517,12 @@
 	}
 	case ETHTOOL_GEEPROM: {
 		struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
+		struct e1000_hw *hw = &adapter->hw;
 		uint16_t *eeprom_buff;
 		void *ptr;
-		int max_len, err = 0;
-
-		max_len = e1000_eeprom_size(&adapter->hw);
+		int err = 0;
 
-		eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+		eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL);
 
 		if(eeprom_buff == NULL)
 			return -ENOMEM;
diff -urN linux-2.5.65-bk1/drivers/net/e1000/e1000_hw.c linux-2.5.65-bk2/drivers/net/e1000/e1000_hw.c
--- linux-2.5.65-bk1/drivers/net/e1000/e1000_hw.c	Mon Mar 17 13:44:48 2003
+++ linux-2.5.65-bk2/drivers/net/e1000/e1000_hw.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -32,6 +32,8 @@
 
 #include "e1000_hw.h"
 
+static int32_t e1000_set_phy_type(struct e1000_hw *hw);
+static void e1000_phy_init_script(struct e1000_hw *hw);
 static int32_t e1000_setup_fiber_link(struct e1000_hw *hw);
 static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
 static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
@@ -42,19 +44,103 @@
 static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count);
 static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw);
 static int32_t e1000_phy_reset_dsp(struct e1000_hw *hw);
+static int32_t e1000_write_eeprom_spi(struct e1000_hw *hw, uint16_t offset,
+                                      uint16_t words, uint16_t *data);
+static int32_t e1000_write_eeprom_microwire(struct e1000_hw *hw,
+                                            uint16_t offset, uint16_t words,
+                                            uint16_t *data);
+static int32_t e1000_spi_eeprom_ready(struct e1000_hw *hw);
 static void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
 static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
 static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count);
-static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
-static void e1000_setup_eeprom(struct e1000_hw *hw);
-static void e1000_clock_eeprom(struct e1000_hw *hw);
-static void e1000_cleanup_eeprom(struct e1000_hw *hw);
+static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count);
+static int32_t e1000_acquire_eeprom(struct e1000_hw *hw);
+static void e1000_release_eeprom(struct e1000_hw *hw);
 static void e1000_standby_eeprom(struct e1000_hw *hw);
 static int32_t e1000_id_led_init(struct e1000_hw * hw);
 
+
+
+/******************************************************************************
+ * Set the phy type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_set_phy_type(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_set_phy_type");
+
+    switch(hw->phy_id) {
+    case M88E1000_E_PHY_ID:
+    case M88E1000_I_PHY_ID:
+    case M88E1011_I_PHY_ID:
+        hw->phy_type = e1000_phy_m88;
+        break;
+    case IGP01E1000_I_PHY_ID:
+        hw->phy_type = e1000_phy_igp;
+        break;
+    default:
+        /* Should never have loaded on this device */
+        hw->phy_type = e1000_phy_undefined;
+        return -E1000_ERR_PHY_TYPE;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * IGP phy init script - initializes the GbE PHY
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_phy_init_script(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_phy_init_script");
+
+    if(hw->phy_init_script) {
+        msec_delay(10);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000);
+        e1000_write_phy_reg(hw,0x0000,0x0140);
+
+        msec_delay(5);
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F95);
+        e1000_write_phy_reg(hw,0x0015,0x0001);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F71);
+        e1000_write_phy_reg(hw,0x0011,0xBD21);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79);
+        e1000_write_phy_reg(hw,0x0019,0x0018);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30);
+        e1000_write_phy_reg(hw,0x0010,0x1600);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31);
+        e1000_write_phy_reg(hw,0x0011,0x0014);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32);
+        e1000_write_phy_reg(hw,0x0012,0x161C);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94);
+        e1000_write_phy_reg(hw,0x0014,0x0003);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96);
+        e1000_write_phy_reg(hw,0x0016,0x003F);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010);
+        e1000_write_phy_reg(hw,0x0010,0x0008);
+
+        e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000);
+        e1000_write_phy_reg(hw,0x0000,0x3300);
+    }
+}
+
 /******************************************************************************
  * Set the mac type member in the hw struct.
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 int32_t
@@ -101,10 +187,19 @@
     case E1000_DEV_ID_82546EB_FIBER:
         hw->mac_type = e1000_82546;
         break;
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+        hw->mac_type = e1000_82541;
+        break;
+    case E1000_DEV_ID_82547EI:
+        hw->mac_type = e1000_82547;
+        break;
     default:
         /* Should never have loaded on this device */
         return -E1000_ERR_MAC_TYPE;
     }
+
+
     return E1000_SUCCESS;
 }
 /******************************************************************************
@@ -119,9 +214,10 @@
     uint32_t ctrl_ext;
     uint32_t icr;
     uint32_t manc;
+    uint32_t led_ctrl;
 
     DEBUGFUNC("e1000_reset_hw");
-    
+
     /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
     if(hw->mac_type == e1000_82542_rev2_0) {
         DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
@@ -145,7 +241,7 @@
 
     /* Delay to allow any outstanding PCI transactions to complete before
      * resetting the device
-     */ 
+     */
     msec_delay(10);
 
     /* Issue a global reset to the MAC.  This will reset the chip's
@@ -156,6 +252,12 @@
     DEBUGOUT("Issuing a global reset to MAC\n");
     ctrl = E1000_READ_REG(hw, CTRL);
 
+    /* Must reset the PHY before resetting the MAC */
+    if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+        E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
+	msec_delay(5);
+    }
+
     if(hw->mac_type > e1000_82543)
         E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
     else
@@ -173,13 +275,25 @@
         msec_delay(2);
     } else {
         /* Wait for EEPROM reload (it happens automatically) */
-        msec_delay(4);
+        msec_delay(5);
         /* Dissable HW ARPs on ASF enabled adapters */
         manc = E1000_READ_REG(hw, MANC);
         manc &= ~(E1000_MANC_ARP_EN);
         E1000_WRITE_REG(hw, MANC, manc);
     }
-    
+
+    if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+        e1000_phy_init_script(hw);
+
+        /* Configure activity LED after PHY reset */
+        led_ctrl = E1000_READ_REG(hw, LEDCTL);
+        led_ctrl &= IGP_ACTIVITY_LED_MASK;
+        led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
+        if(hw->mac_type == e1000_82547)
+            led_ctrl |= IGP_LED3_MODE;
+        E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+    }
+
     /* Clear interrupt mask to stop board from generating interrupts */
     DEBUGOUT("Masking off all interrupts\n");
     E1000_WRITE_REG(hw, IMC, 0xffffffff);
@@ -198,8 +312,8 @@
  * Performs basic configuration of the adapter.
  *
  * hw - Struct containing variables accessed by shared code
- * 
- * Assumes that the controller has previously been reset and is in a 
+ *
+ * Assumes that the controller has previously been reset and is in a
  * post-reset uninitialized state. Initializes the receive address registers,
  * multicast table, and VLAN filter table. Calls routines to setup link
  * configuration and flow control settings. Clears all on-chip counters. Leaves
@@ -224,7 +338,7 @@
         DEBUGOUT("Error Initializing Identification LED\n");
         return ret_val;
     }
-    
+
     /* Set the Media Type and exit with error if it is not valid. */
     if(hw->mac_type != e1000_82543) {
         /* tbi_compatibility is only valid on 82543 */
@@ -327,13 +441,13 @@
 
 /******************************************************************************
  * Configures flow control and link settings.
- * 
+ *
  * hw - Struct containing variables accessed by shared code
- * 
+ *
  * Determines which flow control settings to use. Calls the apropriate media-
  * specific link configuration function. Configures the flow control settings.
  * Assuming the adapter has a valid link partner, a valid link should be
- * established. Assumes the hardware has previously been reset and the 
+ * established. Assumes the hardware has previously been reset and the
  * transmitter and receiver are not enabled.
  *****************************************************************************/
 int32_t
@@ -353,7 +467,7 @@
      * control setting, then the variable hw->fc will
      * be initialized based on a value in the EEPROM.
      */
-    if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+    if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -361,7 +475,7 @@
     if(hw->fc == e1000_fc_default) {
         if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
             hw->fc = e1000_fc_none;
-        else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 
+        else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
                 EEPROM_WORD0F_ASM_DIR)
             hw->fc = e1000_fc_tx_pause;
         else
@@ -390,7 +504,7 @@
      * or e1000_phy_setup() is called.
      */
     if(hw->mac_type == e1000_82543) {
-        ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << 
+        ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
                     SWDPIO__EXT_SHIFT);
         E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
     }
@@ -416,7 +530,7 @@
      * these registers will be set to a default threshold that may be
      * adjusted later by the driver's runtime code.  However, if the
      * ability to transmit pause frames in not enabled, then these
-     * registers will be set to 0. 
+     * registers will be set to 0.
      */
     if(!(hw->fc & e1000_fc_tx_pause)) {
         E1000_WRITE_REG(hw, FCRTL, 0);
@@ -445,7 +559,7 @@
  * link. Assumes the hardware has been previously reset and the transmitter
  * and receiver are not enabled.
  *****************************************************************************/
-static int32_t 
+static int32_t
 e1000_setup_fiber_link(struct e1000_hw *hw)
 {
     uint32_t ctrl;
@@ -457,29 +571,29 @@
 
     DEBUGFUNC("e1000_setup_fiber_link");
 
-    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
-     * set when the optics detect a signal. On older adapters, it will be 
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+     * set when the optics detect a signal. On older adapters, it will be
      * cleared when there is a signal
      */
     ctrl = E1000_READ_REG(hw, CTRL);
     if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
     else signal = 0;
-   
+
     /* Take the link out of reset */
     ctrl &= ~(E1000_CTRL_LRST);
-    
+
     e1000_config_collision_dist(hw);
 
     /* Check for a software override of the flow control settings, and setup
      * the device accordingly.  If auto-negotiation is enabled, then software
      * will have to set the "PAUSE" bits to the correct value in the Tranmsit
      * Config Word Register (TXCW) and re-start auto-negotiation.  However, if
-     * auto-negotiation is disabled, then software will have to manually 
+     * auto-negotiation is disabled, then software will have to manually
      * configure the two flow control enable bits in the CTRL register.
      *
      * The possible values of the "fc" parameter are:
      *      0:  Flow control is completely disabled
-     *      1:  Rx flow control is enabled (we can receive pause frames, but 
+     *      1:  Rx flow control is enabled (we can receive pause frames, but
      *          not send pause frames).
      *      2:  Tx flow control is enabled (we can send pause frames but we do
      *          not support receiving pause frames).
@@ -491,8 +605,8 @@
         txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
         break;
     case e1000_fc_rx_pause:
-        /* RX Flow control is enabled and TX Flow control is disabled by a 
-         * software over-ride. Since there really isn't a way to advertise 
+        /* RX Flow control is enabled and TX Flow control is disabled by a
+         * software over-ride. Since there really isn't a way to advertise
          * that we are capable of RX Pause ONLY, we will advertise that we
          * support both symmetric and asymmetric RX PAUSE. Later, we will
          *  disable the adapter's ability to send PAUSE frames.
@@ -500,7 +614,7 @@
         txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
         break;
     case e1000_fc_tx_pause:
-        /* TX Flow control is enabled, and RX Flow control is disabled, by a 
+        /* TX Flow control is enabled, and RX Flow control is disabled, by a
          * software over-ride.
          */
         txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
@@ -531,8 +645,8 @@
     msec_delay(1);
 
     /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
-     * indication in the Device Status Register.  Time-out if a link isn't 
-     * seen in 500 milliseconds seconds (Auto-negotiation should complete in 
+     * indication in the Device Status Register.  Time-out if a link isn't
+     * seen in 500 milliseconds seconds (Auto-negotiation should complete in
      * less than 500 milliseconds even if the other end is doing it in SW).
      */
     if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
@@ -543,7 +657,7 @@
             if(status & E1000_STATUS_LU) break;
         }
         if(i == (LINK_UP_TIMEOUT / 10)) {
-            /* AutoNeg failed to achieve a link, so we'll call 
+            /* AutoNeg failed to achieve a link, so we'll call
              * e1000_check_for_link. This routine will force the link up if we
              * detect a signal. This will allow us to communicate with
              * non-autonegotiating link partners.
@@ -571,10 +685,10 @@
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
-static int32_t 
+static int32_t
 e1000_setup_copper_link(struct e1000_hw *hw)
 {
-    uint32_t ctrl;
+    uint32_t ctrl, led_ctrl;
     int32_t ret_val;
     uint16_t i;
     uint16_t phy_data;
@@ -604,80 +718,148 @@
     }
     DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
 
-    /* Enable CRS on TX. This must be set for half-duplex operation. */
-    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+    if (hw->phy_type == e1000_phy_igp) {
 
-    /* Options:
-     *   MDI/MDI-X = 0 (default)
-     *   0 - Auto for all speeds
-     *   1 - MDI mode
-     *   2 - MDI-X mode
-     *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-     */
-    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+        ret_val = e1000_phy_reset(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Resetting the PHY\n");
+            return ret_val;
+        }
 
-    switch (hw->mdix) {
-    case 1:
-        phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
-        break;
-    case 2:
-        phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
-        break;
-    case 3:
-        phy_data |= M88E1000_PSCR_AUTO_X_1000T;
-        break;
-    case 0:
-    default:
-        phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-        break;
-    }
+        /* Wait 10ms for MAC to configure PHY from eeprom settings */
+        msec_delay(15);
 
-    /* Options:
-     *   disable_polarity_correction = 0 (default)
-     *       Automatic Correction for Reversed Cable Polarity
-     *   0 - Disabled
-     *   1 - Enabled
-     */
-    phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-    if(hw->disable_polarity_correction == 1)
-        phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
-    }
+        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
 
-    /* Force TX_CLK in the Extended PHY Specific Control Register
-     * to 25MHz clock.
-     */
-    if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+        /* Configure activity LED after PHY reset */
+        led_ctrl = E1000_READ_REG(hw, LEDCTL);
+        led_ctrl &= IGP_ACTIVITY_LED_MASK;
+        led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
+        if(hw->mac_type == e1000_82547)
+            led_ctrl |= IGP_LED3_MODE;
+        E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+
+        if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+            /* Disable SmartSpeed */
+            if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                  &phy_data) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                   phy_data) < 0) {
+                DEBUGOUT("PHY Write Error\n");
+                return -E1000_ERR_PHY;
+            }
+            /* Set auto Master/Slave resolution process */
+            if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            phy_data &= ~CR_1000T_MS_ENABLE;
+            if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data) < 0) {
+                DEBUGOUT("PHY Write Error\n");
+                return -E1000_ERR_PHY;
+            }
+        }
 
-    if (hw->phy_revision < M88E1011_I_REV_4) {
-        /* Configure Master and Slave downshift values */
-        phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
-                      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-        phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
-                     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-        if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* Force MDI for IGP PHY */
+        phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX |
+                      IGP01E1000_PSCR_FORCE_MDI_MDIX);
+
+        hw->mdix = 1;
+
+        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) {
             DEBUGOUT("PHY Write Error\n");
             return -E1000_ERR_PHY;
         }
-    }
 
-    /* SW Reset the PHY so all changes take effect */
-    ret_val = e1000_phy_reset(hw);
-    if(ret_val < 0) {
-        DEBUGOUT("Error Resetting the PHY\n");
-        return ret_val;
+    } else {
+        /* Enable CRS on TX. This must be set for half-duplex operation. */
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+        /* Options:
+         *   MDI/MDI-X = 0 (default)
+         *   0 - Auto for all speeds
+         *   1 - MDI mode
+         *   2 - MDI-X mode
+         *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+         */
+        phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+        switch (hw->mdix) {
+        case 1:
+            phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+            break;
+        case 2:
+            phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+            break;
+        case 3:
+            phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+            break;
+        case 0:
+        default:
+            phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+            break;
+        }
+
+        /* Options:
+         *   disable_polarity_correction = 0 (default)
+         *       Automatic Correction for Reversed Cable Polarity
+         *   0 - Disabled
+         *   1 - Enabled
+         */
+        phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+        if(hw->disable_polarity_correction == 1)
+            phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+        if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* Force TX_CLK in the Extended PHY Specific Control Register
+         * to 25MHz clock.
+         */
+        if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+        if (hw->phy_revision < M88E1011_I_REV_4) {
+            /* Configure Master and Slave downshift values */
+            phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+                          M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+            phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+                         M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+            if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                   phy_data) < 0) {
+                DEBUGOUT("PHY Write Error\n");
+                return -E1000_ERR_PHY;
+            }
+        }
+
+        /* SW Reset the PHY so all changes take effect */
+        ret_val = e1000_phy_reset(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Resetting the PHY\n");
+            return ret_val;
+        }
     }
-    
+
     /* Options:
      *   autoneg = 1 (default)
      *      PHY will advertise value(s) parsed from
@@ -736,6 +918,7 @@
                 return ret_val;
             }
         }
+        hw->get_link_status = TRUE;
     } else {
         DEBUGOUT("Forcing speed and duplex\n");
         ret_val = e1000_phy_force_speed_duplex(hw);
@@ -1014,23 +1197,41 @@
     /* Write the configured values back to the Device Control Reg. */
     E1000_WRITE_REG(hw, CTRL, ctrl);
 
-    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
+    if (hw->phy_type == e1000_phy_m88) {
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
 
-    /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
-     * forced whenever speed are duplex are forced.
-     */
-    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
-    }
-    DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+        /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+         * forced whenever speed are duplex are forced.
+         */
+        phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+        if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+        DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+
+        /* Need to reset the PHY or these changes will be ignored */
+        mii_ctrl_reg |= MII_CR_RESET;
+    } else {
+        /* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+         * forced whenever speed or duplex are forced.
+         */
+        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+        phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
 
-    /* Need to reset the PHY or these changes will be ignored */
-    mii_ctrl_reg |= MII_CR_RESET;
+        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+    }
 
     /* Write back the modified PHY MII control register. */
     if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
@@ -1069,7 +1270,7 @@
         }
         if(i == 0) { /* We didn't get link */
             /* Reset the DSP and wait again for link. */
-            
+
             ret_val = e1000_phy_reset_dsp(hw);
             if(ret_val < 0) {
                 DEBUGOUT("Error Resetting PHY DSP\n");
@@ -1093,32 +1294,34 @@
             }
         }
     }
-    
-    /* Because we reset the PHY above, we need to re-force TX_CLK in the
-     * Extended PHY Specific Control Register to 25MHz clock.  This value
-     * defaults back to a 2.5MHz clock when the PHY is reset.
-     */
-    if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    phy_data |= M88E1000_EPSCR_TX_CLK_25;
-    if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
-    }
 
-    /* In addition, because of the s/w reset above, we need to enable CRS on
-     * TX.  This must be set for both full and half duplex operation.
-     */
-    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
+    if (hw->phy_type == e1000_phy_m88) {
+        /* Because we reset the PHY above, we need to re-force TX_CLK in the
+         * Extended PHY Specific Control Register to 25MHz clock.  This value
+         * defaults back to a 2.5MHz clock when the PHY is reset.
+         */
+        if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= M88E1000_EPSCR_TX_CLK_25;
+        if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* In addition, because of the s/w reset above, we need to enable CRS on
+         * TX.  This must be set for both full and half duplex operation.
+         */
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+        if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
     }
     return 0;
 }
@@ -1136,6 +1339,8 @@
 {
     uint32_t tctl;
 
+    DEBUGFUNC("e1000_config_collision_dist");
+
     tctl = E1000_READ_REG(hw, TCTL);
 
     tctl &= ~E1000_TCTL_COLD;
@@ -1172,22 +1377,43 @@
     /* Set up duplex in the Device Control and Transmit Control
      * registers depending on negotiated values.
      */
-    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
-    else ctrl &= ~E1000_CTRL_FD;
+    if (hw->phy_type == e1000_phy_igp) {
+        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD;
+        else ctrl &= ~E1000_CTRL_FD;
 
-    e1000_config_collision_dist(hw);
+        e1000_config_collision_dist(hw);
 
-    /* Set up speed in the Device Control register depending on
-     * negotiated values.
-     */
-    if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
-        ctrl |= E1000_CTRL_SPD_1000;
-    else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
-        ctrl |= E1000_CTRL_SPD_100;
+        /* Set up speed in the Device Control register depending on
+         * negotiated values.
+         */
+        if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+           IGP01E1000_PSSR_SPEED_1000MBPS)
+            ctrl |= E1000_CTRL_SPD_1000;
+        else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+                IGP01E1000_PSSR_SPEED_100MBPS)
+            ctrl |= E1000_CTRL_SPD_100;
+    } else {
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
+        else ctrl &= ~E1000_CTRL_FD;
+
+        e1000_config_collision_dist(hw);
+
+        /* Set up speed in the Device Control register depending on
+         * negotiated values.
+         */
+        if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+            ctrl |= E1000_CTRL_SPD_1000;
+        else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+            ctrl |= E1000_CTRL_SPD_100;
+    }
     /* Write the configured values back to the Device Control Reg. */
     E1000_WRITE_REG(hw, CTRL, ctrl);
     return 0;
@@ -1195,7 +1421,7 @@
 
 /******************************************************************************
  * Forces the MAC's flow control settings.
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *
  * Sets the TFCE and RFCE bits in the device control register to reflect
@@ -1262,7 +1488,7 @@
 
 /******************************************************************************
  * Configures flow control settings after link is established
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *
  * Should be called immediately after a valid link has been established.
@@ -1484,9 +1710,9 @@
     uint16_t lp_capability;
 
     DEBUGFUNC("e1000_check_for_link");
-    
-    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
-     * set when the optics detect a signal. On older adapters, it will be 
+
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+     * set when the optics detect a signal. On older adapters, it will be
      * cleared when there is a signal
      */
     if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
@@ -1519,6 +1745,10 @@
 
         if(phy_data & MII_SR_LINK_STATUS) {
             hw->get_link_status = FALSE;
+            /* Check if there was DownShift, must be checked immediately after
+             * link-up */
+            e1000_check_downshift(hw);
+
         } else {
             /* No link detected */
             return 0;
@@ -1547,7 +1777,7 @@
             }
         }
 
-        /* Configure Flow Control now that Auto-Neg has completed. First, we 
+        /* Configure Flow Control now that Auto-Neg has completed. First, we
          * need to restore the desired flow control settings because we may
          * have had to re-autoneg with a different link partner.
          */
@@ -1576,7 +1806,7 @@
                                 NWAY_LPAR_100TX_HD_CAPS |
                                 NWAY_LPAR_100TX_FD_CAPS |
                                 NWAY_LPAR_100T4_CAPS)) {
-                /* If our link partner advertises anything in addition to 
+                /* If our link partner advertises anything in addition to
                  * gigabit, we do not need to enable TBI compatibility.
                  */
                 if(hw->tbi_compatibility_on) {
@@ -1780,7 +2010,7 @@
     uint32_t mask;
 
     /* We need to shift "count" number of bits out to the PHY. So, the value
-     * in the "data" parameter will be shifted out to the PHY one bit at a 
+     * in the "data" parameter will be shifted out to the PHY one bit at a
      * time. In order to do this, "data" must be broken down into bits.
      */
     mask = 0x01;
@@ -1817,7 +2047,7 @@
 *
 * hw - Struct containing variables accessed by shared code
 *
-* Bits are shifted in in MSB to LSB order. 
+* Bits are shifted in in MSB to LSB order.
 ******************************************************************************/
 static uint16_t
 e1000_shift_in_mdi_bits(struct e1000_hw *hw)
@@ -1832,7 +2062,7 @@
      * These two bits are ignored by us and thrown away. Bits are "shifted in"
      * by raising the input to the Management Data Clock (setting the MDC bit),
      * and then reading the value of the MDIO bit.
-     */ 
+     */
     ctrl = E1000_READ_REG(hw, CTRL);
 
     /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
@@ -1892,7 +2122,7 @@
          * PHY to retrieve the desired data.
          */
         mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
-                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (phy_addr << E1000_MDIC_PHY_SHIFT) |
                 (E1000_MDIC_OP_READ));
 
         E1000_WRITE_REG(hw, MDIC, mdic);
@@ -1930,7 +2160,7 @@
          * READ operation is performed.  These two bits are thrown away
          * followed by a shift in of 16 bits which contains the desired data.
          */
-        mdic = ((reg_addr) | (phy_addr << 5) | 
+        mdic = ((reg_addr) | (phy_addr << 5) |
                 (PHY_OP_READ << 10) | (PHY_SOF << 12));
 
         e1000_shift_out_mdi_bits(hw, mdic, 14);
@@ -1974,7 +2204,7 @@
          */
         mdic = (((uint32_t) phy_data) |
                 (reg_addr << E1000_MDIC_REG_SHIFT) |
-                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (phy_addr << E1000_MDIC_PHY_SHIFT) |
                 (E1000_MDIC_OP_WRITE));
 
         E1000_WRITE_REG(hw, MDIC, mdic);
@@ -1992,12 +2222,12 @@
     } else {
         /* We'll need to use the SW defined pins to shift the write command
          * out to the PHY. We first send a preamble to the PHY to signal the
-         * beginning of the MII instruction.  This is done by sending 32 
+         * beginning of the MII instruction.  This is done by sending 32
          * consecutive "1" bits.
          */
         e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
 
-        /* Now combine the remaining required fields that will indicate a 
+        /* Now combine the remaining required fields that will indicate a
          * write operation. We use this method instead of calling the
          * e1000_shift_out_mdi_bits routine for each field in the command. The
          * format of a MII write instruction is as follows:
@@ -2010,6 +2240,7 @@
 
         e1000_shift_out_mdi_bits(hw, mdic, 32);
     }
+
     return 0;
 }
 
@@ -2021,8 +2252,7 @@
 void
 e1000_phy_hw_reset(struct e1000_hw *hw)
 {
-    uint32_t ctrl;
-    uint32_t ctrl_ext;
+    uint32_t ctrl, ctrl_ext, led_ctrl;
 
     DEBUGFUNC("e1000_phy_hw_reset");
 
@@ -2053,6 +2283,21 @@
         E1000_WRITE_FLUSH(hw);
     }
     udelay(150);
+
+    if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return;
+        }
+
+        /* Configure activity LED after PHY reset */
+        led_ctrl = E1000_READ_REG(hw, LEDCTL);
+        led_ctrl &= IGP_ACTIVITY_LED_MASK;
+        led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
+        if(hw->mac_type == e1000_82547)
+            led_ctrl |= IGP_LED3_MODE;
+        E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+    }
 }
 
 /******************************************************************************
@@ -2079,6 +2324,9 @@
         return -E1000_ERR_PHY;
     }
     udelay(1);
+    if (hw->phy_type == e1000_phy_igp) {
+        e1000_phy_init_script(hw);
+    }
     return 0;
 }
 
@@ -2092,6 +2340,7 @@
 {
     uint16_t phy_id_high, phy_id_low;
     boolean_t match = FALSE;
+    int32_t phy_init_status;
 
     DEBUGFUNC("e1000_detect_gig_phy");
 
@@ -2101,7 +2350,7 @@
         return -E1000_ERR_PHY;
     }
     hw->phy_id = (uint32_t) (phy_id_high << 16);
-    udelay(2);
+    udelay(20);
     if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
         DEBUGOUT("PHY Read Error\n");
         return -E1000_ERR_PHY;
@@ -2121,11 +2370,17 @@
     case e1000_82546:
         if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
         break;
+    case e1000_82541:
+    case e1000_82547:
+        if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
+        break;
     default:
         DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
         return -E1000_ERR_CONFIG;
     }
-    if(match) {
+    phy_init_status = e1000_set_phy_type(hw);
+
+    if ((match) && (phy_init_status == E1000_SUCCESS)) {
         DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
         return 0;
     }
@@ -2143,7 +2398,7 @@
 {
     int32_t ret_val = -E1000_ERR_PHY;
     DEBUGFUNC("e1000_phy_reset_dsp");
-    
+
     do {
         if(e1000_write_phy_reg(hw, 29, 0x001d) < 0) break;
         if(e1000_write_phy_reg(hw, 30, 0x00c1) < 0) break;
@@ -2156,74 +2411,177 @@
 }
 
 /******************************************************************************
-* Get PHY information from various PHY registers
+* Get PHY information from various PHY registers for igp PHY only.
 *
 * hw - Struct containing variables accessed by shared code
 * phy_info - PHY information structure
 ******************************************************************************/
 int32_t
-e1000_phy_get_info(struct e1000_hw *hw,
-                   struct e1000_phy_info *phy_info)
+e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
 {
-    int32_t ret_val = -E1000_ERR_PHY;
-    uint16_t phy_data;
+    uint16_t phy_data, polarity, min_length, max_length, average;
 
-    DEBUGFUNC("e1000_phy_get_info");
+    DEBUGFUNC("e1000_phy_igp_get_info");
 
-    phy_info->cable_length = e1000_cable_length_undefined;
-    phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined;
-    phy_info->cable_polarity = e1000_rev_polarity_undefined;
-    phy_info->polarity_correction = e1000_polarity_reversal_undefined;
-    phy_info->mdix_mode = e1000_auto_x_mode_undefined;
-    phy_info->local_rx = e1000_1000t_rx_status_undefined;
-    phy_info->remote_rx = e1000_1000t_rx_status_undefined;
+    /* The downshift status is checked only once, after link is established,
+     * and it stored in the hw->speed_downgraded parameter. */
+    phy_info->downshift = hw->speed_downgraded;
 
-    if(hw->media_type != e1000_media_type_copper) {
-        DEBUGOUT("PHY info is only valid for copper media\n");
-        return -E1000_ERR_CONFIG;
-    }
+    /* IGP01E1000 does not need to support it. */
+    phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal;
 
-    do {
-        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
-        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
-        if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
-            DEBUGOUT("PHY info is only valid if link is up\n");
-            return -E1000_ERR_CONFIG;
-        }
+    /* IGP01E1000 always correct polarity reversal */
+    phy_info->polarity_correction = e1000_polarity_reversal_enabled;
 
-        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
-            break;
-        phy_info->extended_10bt_distance =
-            (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
-            M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
-        phy_info->polarity_correction =
-            (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
-            M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+    /* Check polarity status */
+    if(e1000_check_polarity(hw, &polarity) < 0)
+        return -E1000_ERR_PHY;
 
-        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
-            break;
-        phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
-            M88E1000_PSSR_REV_POLARITY_SHIFT;
-        phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
-            M88E1000_PSSR_MDIX_SHIFT;
-        if(phy_data & M88E1000_PSSR_1000MBS) {
-            /* Cable Length Estimation and Local/Remote Receiver Informatoion
-             * are only valid at 1000 Mbps
-             */
-            phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-                                      M88E1000_PSSR_CABLE_LENGTH_SHIFT);
-            if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) 
-                break;
-            phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
-                SR_1000T_LOCAL_RX_STATUS_SHIFT;
-            phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
-                SR_1000T_REMOTE_RX_STATUS_SHIFT;
-        }
-        ret_val = 0;
-    } while(0);
+    phy_info->cable_polarity = polarity;
 
-    if(ret_val < 0) DEBUGOUT("PHY Read Error\n");
-    return ret_val;
+    if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
+                          IGP01E1000_PSSR_MDIX_SHIFT;
+
+    if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+       IGP01E1000_PSSR_SPEED_1000MBPS) {
+        /* Local/Remote Receiver Information are only valid at 1000 Mbps */
+        if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+
+        phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                             SR_1000T_LOCAL_RX_STATUS_SHIFT;
+        phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                              SR_1000T_REMOTE_RX_STATUS_SHIFT;
+
+        /* Get cable length */
+        if(e1000_get_cable_length(hw, &min_length, &max_length) < 0)
+            return -E1000_ERR_PHY;
+
+        /* transalte to old method */
+        average = (max_length + min_length) / 2;
+
+        if(average <= e1000_igp_cable_length_50)
+            phy_info->cable_length = e1000_cable_length_50;
+        else if(average <= e1000_igp_cable_length_80)
+            phy_info->cable_length = e1000_cable_length_50_80;
+        else if(average <= e1000_igp_cable_length_110)
+            phy_info->cable_length = e1000_cable_length_80_110;
+        else if(average <= e1000_igp_cable_length_140)
+            phy_info->cable_length = e1000_cable_length_110_140;
+        else
+            phy_info->cable_length = e1000_cable_length_140;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers fot m88 PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
+{
+    uint16_t phy_data, polarity;
+
+    DEBUGFUNC("e1000_phy_m88_get_info");
+
+    /* The downshift status is checked only once, after link is established,
+     * and it stored in the hw->speed_downgraded parameter. */
+    phy_info->downshift = hw->speed_downgraded;
+
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->extended_10bt_distance =
+        (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+        M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+    phy_info->polarity_correction =
+        (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+        M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+    /* Check polarity status */
+    if(e1000_check_polarity(hw, &polarity) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->cable_polarity = polarity;
+
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+                          M88E1000_PSSR_MDIX_SHIFT;
+
+    if(phy_data & M88E1000_PSSR_1000MBS) {
+        /* Cable Length Estimation and Local/Remote Receiver Informatoion
+         * are only valid at 1000 Mbps
+         */
+        phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                                  M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+
+        if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+
+        phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                             SR_1000T_LOCAL_RX_STATUS_SHIFT;
+
+        phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                              SR_1000T_REMOTE_RX_STATUS_SHIFT;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_get_info(struct e1000_hw *hw,
+                   struct e1000_phy_info *phy_info)
+{
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_phy_get_info");
+
+    phy_info->cable_length = e1000_cable_length_undefined;
+    phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined;
+    phy_info->cable_polarity = e1000_rev_polarity_undefined;
+    phy_info->downshift = e1000_downshift_undefined;
+    phy_info->polarity_correction = e1000_polarity_reversal_undefined;
+    phy_info->mdix_mode = e1000_auto_x_mode_undefined;
+    phy_info->local_rx = e1000_1000t_rx_status_undefined;
+    phy_info->remote_rx = e1000_1000t_rx_status_undefined;
+
+    if(hw->media_type != e1000_media_type_copper) {
+        DEBUGOUT("PHY info is only valid for copper media\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+        DEBUGOUT("PHY info is only valid if link is up\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    if (hw->phy_type == e1000_phy_igp)
+        return e1000_phy_igp_get_info(hw, phy_info);
+    else
+        return e1000_phy_m88_get_info(hw, phy_info);
 }
 
 int32_t
@@ -2239,6 +2597,109 @@
     return 0;
 }
 
+
+/******************************************************************************
+ * Sets up eeprom variables in the hw struct.  Must be called after mac_type
+ * is configured.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_init_eeprom_params(struct e1000_hw *hw)
+{
+    struct e1000_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd = E1000_READ_REG(hw, EECD);
+    uint16_t eeprom_size;
+
+    DEBUGFUNC("e1000_init_eeprom_params");
+
+    switch (hw->mac_type) {
+    case e1000_82542_rev2_0:
+    case e1000_82542_rev2_1:
+    case e1000_82543:
+    case e1000_82544:
+        eeprom->type = e1000_eeprom_microwire;
+        eeprom->word_size = 64;
+        eeprom->opcode_bits = 3;
+        eeprom->address_bits = 6;
+        eeprom->delay_usec = 50;
+        break;
+    case e1000_82540:
+    case e1000_82545:
+    case e1000_82546:
+        eeprom->type = e1000_eeprom_microwire;
+        eeprom->opcode_bits = 3;
+        eeprom->delay_usec = 50;
+        if(eecd & E1000_EECD_SIZE) {
+            eeprom->word_size = 256;
+            eeprom->address_bits = 8;
+        } else {
+            eeprom->word_size = 64;
+            eeprom->address_bits = 6;
+        }
+        break;
+    case e1000_82541:
+    case e1000_82547:
+    default:
+        if (eecd & E1000_EECD_TYPE) {
+            eeprom->type = e1000_eeprom_spi;
+            eeprom->opcode_bits = 8;
+            eeprom->delay_usec = 1;
+            if (eecd & E1000_EECD_ADDR_BITS) {
+                eeprom->page_size = 32;
+                eeprom->address_bits = 16;
+            } else {
+                eeprom->page_size = 8;
+                eeprom->address_bits = 8;
+            }
+        } else {
+            eeprom->type = e1000_eeprom_microwire;
+            eeprom->opcode_bits = 3;
+            eeprom->delay_usec = 50;
+            if (eecd & E1000_EECD_ADDR_BITS) {
+                eeprom->word_size = 256;
+                eeprom->address_bits = 8;
+            } else {
+                eeprom->word_size = 64;
+                eeprom->address_bits = 6;
+            }
+        }
+        break;
+    }
+
+    if (eeprom->type == e1000_eeprom_spi) {
+        eeprom->word_size = 64;
+        if (e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) {
+            eeprom_size &= EEPROM_SIZE_MASK;
+
+            switch (eeprom_size) {
+                case EEPROM_SIZE_16KB:
+                    eeprom->word_size = 8192;
+                    break;
+                case EEPROM_SIZE_8KB:
+                    eeprom->word_size = 4096;
+                    break;
+                case EEPROM_SIZE_4KB:
+                    eeprom->word_size = 2048;
+                    break;
+                case EEPROM_SIZE_2KB:
+                    eeprom->word_size = 1024;
+                    break;
+                case EEPROM_SIZE_1KB:
+                    eeprom->word_size = 512;
+                    break;
+                case EEPROM_SIZE_512B:
+                    eeprom->word_size = 256;
+                    break;
+                case EEPROM_SIZE_128B:
+                default:
+                    eeprom->word_size = 64;
+                    break;
+            }
+        }
+    }
+}
+
 /******************************************************************************
  * Raises the EEPROM's clock input.
  *
@@ -2255,26 +2716,26 @@
     *eecd = *eecd | E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, *eecd);
     E1000_WRITE_FLUSH(hw);
-    udelay(50);
+    udelay(hw->eeprom.delay_usec);
 }
 
 /******************************************************************************
  * Lowers the EEPROM's clock input.
  *
- * hw - Struct containing variables accessed by shared code 
+ * hw - Struct containing variables accessed by shared code
  * eecd - EECD's current value
  *****************************************************************************/
 static void
 e1000_lower_ee_clk(struct e1000_hw *hw,
                    uint32_t *eecd)
 {
-    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then 
-     * wait 50 microseconds. 
+    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+     * wait 50 microseconds.
      */
     *eecd = *eecd & ~E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, *eecd);
     E1000_WRITE_FLUSH(hw);
-    udelay(50);
+    udelay(hw->eeprom.delay_usec);
 }
 
 /******************************************************************************
@@ -2289,16 +2750,21 @@
                         uint16_t data,
                         uint16_t count)
 {
+    struct e1000_eeprom_info *eeprom = &hw->eeprom;
     uint32_t eecd;
     uint32_t mask;
 
     /* We need to shift "count" bits out to the EEPROM. So, value in the
      * "data" parameter will be shifted out to the EEPROM one bit at a time.
-     * In order to do this, "data" must be broken down into bits. 
+     * In order to do this, "data" must be broken down into bits.
      */
     mask = 0x01 << (count - 1);
     eecd = E1000_READ_REG(hw, EECD);
-    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    if (eeprom->type == e1000_eeprom_microwire) {
+        eecd &= ~E1000_EECD_DO;
+    } else if (eeprom->type == e1000_eeprom_spi) {
+        eecd |= E1000_EECD_DO;
+    }
     do {
         /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
          * and then raising and then lowering the clock (the SK bit controls
@@ -2313,7 +2779,7 @@
         E1000_WRITE_REG(hw, EECD, eecd);
         E1000_WRITE_FLUSH(hw);
 
-        udelay(50);
+        udelay(eeprom->delay_usec);
 
         e1000_raise_ee_clk(hw, &eecd);
         e1000_lower_ee_clk(hw, &eecd);
@@ -2333,7 +2799,7 @@
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static uint16_t
-e1000_shift_in_ee_bits(struct e1000_hw *hw)
+e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count)
 {
     uint32_t eecd;
     uint32_t i;
@@ -2351,7 +2817,7 @@
     eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
     data = 0;
 
-    for(i = 0; i < 16; i++) {
+    for(i = 0; i < count; i++) {
         data = data << 1;
         e1000_raise_ee_clk(hw, &eecd);
 
@@ -2372,104 +2838,196 @@
  *
  * hw - Struct containing variables accessed by shared code
  *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This 
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
  * function should be called before issuing a command to the EEPROM.
  *****************************************************************************/
-static void
-e1000_setup_eeprom(struct e1000_hw *hw)
+static int32_t
+e1000_acquire_eeprom(struct e1000_hw *hw)
 {
-    uint32_t eecd;
+    struct e1000_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd, i=0;
+
+    DEBUGFUNC("e1000_acquire_eeprom");
 
     eecd = E1000_READ_REG(hw, EECD);
 
-    /* Clear SK and DI */
-    eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
-    E1000_WRITE_REG(hw, EECD, eecd);
+    /* Request EEPROM Access */
+    if(hw->mac_type > e1000_82544) {
+        eecd |= E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        eecd = E1000_READ_REG(hw, EECD);
+        while((!(eecd & E1000_EECD_GNT)) &&
+              (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+            i++;
+            udelay(5);
+            eecd = E1000_READ_REG(hw, EECD);
+        }
+        if(!(eecd & E1000_EECD_GNT)) {
+            eecd &= ~E1000_EECD_REQ;
+            E1000_WRITE_REG(hw, EECD, eecd);
+            DEBUGOUT("Could not acquire EEPROM grant\n");
+            return -E1000_ERR_EEPROM;
+        }
+    }
 
-    /* Set CS */
-    eecd |= E1000_EECD_CS;
-    E1000_WRITE_REG(hw, EECD, eecd);
+    /* Setup EEPROM for Read/Write */
+
+    if (eeprom->type == e1000_eeprom_microwire) {
+        /* Clear SK and DI */
+        eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        /* Set CS */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    } else if (eeprom->type == e1000_eeprom_spi) {
+        /* Clear SK and CS */
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+        udelay(1);
+    }
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
  * Returns EEPROM to a "standby" state
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static void
 e1000_standby_eeprom(struct e1000_hw *hw)
 {
+    struct e1000_eeprom_info *eeprom = &hw->eeprom;
     uint32_t eecd;
 
     eecd = E1000_READ_REG(hw, EECD);
 
-    /* Deselct EEPROM */
-    eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-    E1000_WRITE_REG(hw, EECD, eecd);
-    E1000_WRITE_FLUSH(hw);
-    udelay(50);
+    if(eeprom->type == e1000_eeprom_microwire) {
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        udelay(eeprom->delay_usec);
 
-    /* Clock high */
-    eecd |= E1000_EECD_SK;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    E1000_WRITE_FLUSH(hw);
-    udelay(50);
+        /* Clock high */
+        eecd |= E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        udelay(eeprom->delay_usec);
 
-    /* Select EEPROM */
-    eecd |= E1000_EECD_CS;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    E1000_WRITE_FLUSH(hw);
-    udelay(50);
+        /* Select EEPROM */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        udelay(eeprom->delay_usec);
 
-    /* Clock low */
-    eecd &= ~E1000_EECD_SK;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    E1000_WRITE_FLUSH(hw);
-    udelay(50);
+        /* Clock low */
+        eecd &= ~E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        udelay(eeprom->delay_usec);
+    } else if(eeprom->type == e1000_eeprom_spi) {
+        /* Toggle CS to flush commands */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        udelay(eeprom->delay_usec);
+        eecd &= ~E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        udelay(eeprom->delay_usec);
+    }
 }
 
 /******************************************************************************
- * Raises then lowers the EEPROM's clock pin
+ * Terminates a command by inverting the EEPROM's chip select pin
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static void
-e1000_clock_eeprom(struct e1000_hw *hw)
+e1000_release_eeprom(struct e1000_hw *hw)
 {
     uint32_t eecd;
 
+    DEBUGFUNC("e1000_release_eeprom");
+
     eecd = E1000_READ_REG(hw, EECD);
 
-    /* Rising edge of clock */
-    eecd |= E1000_EECD_SK;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    E1000_WRITE_FLUSH(hw);
-    udelay(50);
+    if (hw->eeprom.type == e1000_eeprom_spi) {
+        eecd |= E1000_EECD_CS;  /* Pull CS high */
+        eecd &= ~E1000_EECD_SK; /* Lower SCK */
 
-    /* Falling edge of clock */
-    eecd &= ~E1000_EECD_SK;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    E1000_WRITE_FLUSH(hw);
-    udelay(50);
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        udelay(hw->eeprom.delay_usec);
+    } else if(hw->eeprom.type == e1000_eeprom_microwire) {
+        /* cleanup eeprom */
+
+        /* CS on Microwire is active-high */
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        /* Rising edge of clock */
+        eecd |= E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        udelay(hw->eeprom.delay_usec);
+
+        /* Falling edge of clock */
+        eecd &= ~E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        udelay(hw->eeprom.delay_usec);
+    }
+
+    /* Stop requesting EEPROM access */
+    if(hw->mac_type > e1000_82544) {
+        eecd &= ~E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    }
 }
 
 /******************************************************************************
- * Terminates a command by lowering the EEPROM's chip select pin
+ * Reads a 16 bit word from the EEPROM.
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
-static void
-e1000_cleanup_eeprom(struct e1000_hw *hw)
+int32_t
+e1000_spi_eeprom_ready(struct e1000_hw *hw)
 {
-    uint32_t eecd;
+    uint16_t retry_count = 0;
+    uint8_t spi_stat_reg;
 
-    eecd = E1000_READ_REG(hw, EECD);
+    DEBUGFUNC("e1000_spi_eeprom_ready");
 
-    eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+    /* Read "Status Register" repeatedly until the LSB is cleared.  The
+     * EEPROM will signal that the command has been completed by clearing
+     * bit 0 of the internal status register.  If it's not cleared within
+     * 5 milliseconds, then error out.
+     */
+    retry_count = 0;
+    do {
+        e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+                                hw->eeprom.opcode_bits);
+        spi_stat_reg = (uint8_t)e1000_shift_in_ee_bits(hw, 8);
+        if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+            break;
 
-    E1000_WRITE_REG(hw, EECD, eecd);
+        udelay(5);
+        retry_count += 5;
+
+    } while(retry_count < EEPROM_MAX_RETRY_SPI);
+
+    /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+     * only 0-5mSec on 5V devices)
+     */
+    if(retry_count >= EEPROM_MAX_RETRY_SPI) {
+        DEBUGOUT("SPI EEPROM Status error\n");
+        return -E1000_ERR_EEPROM;
+    }
 
-    e1000_clock_eeprom(hw);
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -2477,71 +3035,76 @@
  *
  * hw - Struct containing variables accessed by shared code
  * offset - offset of  word in the EEPROM to read
- * data - word read from the EEPROM 
+ * data - word read from the EEPROM
+ * words - number of words to read
  *****************************************************************************/
 int32_t
 e1000_read_eeprom(struct e1000_hw *hw,
                   uint16_t offset,
+                  uint16_t words,
                   uint16_t *data)
 {
-    uint32_t eecd;
+    struct e1000_eeprom_info *eeprom = &hw->eeprom;
     uint32_t i = 0;
-    boolean_t large_eeprom = FALSE;
 
     DEBUGFUNC("e1000_read_eeprom");
 
-    /* Request EEPROM Access */
-    if(hw->mac_type > e1000_82544) {
-        eecd = E1000_READ_REG(hw, EECD);
-        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
-        eecd |= E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
-        eecd = E1000_READ_REG(hw, EECD);
-        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
-            i++;
-            udelay(5);
-            eecd = E1000_READ_REG(hw, EECD);
-        }
-        if(!(eecd & E1000_EECD_GNT)) {
-            eecd &= ~E1000_EECD_REQ;
-            E1000_WRITE_REG(hw, EECD, eecd);
-            DEBUGOUT("Could not acquire EEPROM grant\n");
-            return -E1000_ERR_EEPROM;
-        }
+    /* A check for invalid values:  offset too large, too many words, and not
+     * enough words.
+     */
+    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+       (words == 0)) {
+        DEBUGOUT("\"words\" parameter out of bounds\n");
+        return -E1000_ERR_EEPROM;
     }
 
-    /*  Prepare the EEPROM for reading  */
-    e1000_setup_eeprom(hw);
+    /* Prepare the EEPROM for reading  */
+    if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+        return -E1000_ERR_EEPROM;
 
-    /*  Send the READ command (opcode + addr)  */
-    e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
-    if(large_eeprom) {
-        /* If we have a 256 word EEPROM, there are 8 address bits */
-        e1000_shift_out_ee_bits(hw, offset, 8);
-    } else {
-        /* If we have a 64 word EEPROM, there are 6 address bits */
-        e1000_shift_out_ee_bits(hw, offset, 6);
-    }
+    if(eeprom->type == e1000_eeprom_spi) {
+        uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
 
-    /* Read the data */
-    *data = e1000_shift_in_ee_bits(hw);
+        if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
 
-    /* End this read operation */
-    e1000_standby_eeprom(hw);
+        e1000_standby_eeprom(hw);
 
-    /* Stop requesting EEPROM access */
-    if(hw->mac_type > e1000_82544) {
-        eecd = E1000_READ_REG(hw, EECD);
-        eecd &= ~E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
+        /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+        if((eeprom->address_bits == 8) && (offset >= 128))
+            read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+        /* Send the READ command (opcode + addr)  */
+        e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+        e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits);
+    }
+    else if(eeprom->type == e1000_eeprom_microwire) {
+        /* Send the READ command (opcode + addr)  */
+        e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
+                                eeprom->opcode_bits);
+        e1000_shift_out_ee_bits(hw, offset, eeprom->address_bits);
+    }
+
+    /* Read the data.  The address of the eeprom internally increments with
+     * each word (microwire) or byte (spi) being read, saving on the overhead
+     * of eeprom setup and tear-down.  The address counter will roll over if
+     * reading beyond the size of the eeprom, thus allowing the entire memory
+     * to be read starting from any offset. */
+    for (i = 0; i < words; i++) {
+        uint16_t word_in = e1000_shift_in_ee_bits(hw, 16);
+        if (eeprom->type == e1000_eeprom_spi)
+            word_in = (word_in >> 8) | (word_in << 8);
+        data[i] = word_in;
     }
 
+    /* End this read operation */
+    e1000_release_eeprom(hw);
+
     return 0;
 }
 
 /******************************************************************************
  * Verifies that the EEPROM has a valid checksum
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *
  * Reads the first 64 16 bit words of the EEPROM and sums the values read.
@@ -2557,7 +3120,7 @@
     DEBUGFUNC("e1000_validate_eeprom_checksum");
 
     for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
-        if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+        if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
             DEBUGOUT("EEPROM Read Error\n");
             return -E1000_ERR_EEPROM;
         }
@@ -2567,7 +3130,7 @@
     if(checksum == (uint16_t) EEPROM_SUM) {
         return 0;
     } else {
-        DEBUGOUT("EEPROM Checksum Invalid\n");    
+        DEBUGOUT("EEPROM Checksum Invalid\n");
         return -E1000_ERR_EEPROM;
     }
 }
@@ -2589,14 +3152,14 @@
     DEBUGFUNC("e1000_update_eeprom_checksum");
 
     for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
-        if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+        if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
             DEBUGOUT("EEPROM Read Error\n");
             return -E1000_ERR_EEPROM;
         }
         checksum += eeprom_data;
     }
     checksum = (uint16_t) EEPROM_SUM - checksum;
-    if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) {
+    if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
         DEBUGOUT("EEPROM Write Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -2604,118 +3167,201 @@
 }
 
 /******************************************************************************
- * Writes a 16 bit word to a given offset in the EEPROM.
+ * Parent function for writing words to the different EEPROM types.
  *
  * hw - Struct containing variables accessed by shared code
  * offset - offset within the EEPROM to be written to
- * data - 16 bit word to be writen to the EEPROM
+ * words - number of words to write
+ * data - 16 bit word to be written to the EEPROM
  *
- * If e1000_update_eeprom_checksum is not called after this function, the 
+ * If e1000_update_eeprom_checksum is not called after this function, the
  * EEPROM will most likely contain an invalid checksum.
  *****************************************************************************/
 int32_t
 e1000_write_eeprom(struct e1000_hw *hw,
                    uint16_t offset,
-                   uint16_t data)
+                   uint16_t words,
+                   uint16_t *data)
 {
-    uint32_t eecd;
-    uint32_t i = 0;
+    struct e1000_eeprom_info *eeprom = &hw->eeprom;
     int32_t status = 0;
-    boolean_t large_eeprom = FALSE;
 
     DEBUGFUNC("e1000_write_eeprom");
 
-    /* Request EEPROM Access */
-    if(hw->mac_type > e1000_82544) {
-        eecd = E1000_READ_REG(hw, EECD);
-        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
-        eecd |= E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
-        eecd = E1000_READ_REG(hw, EECD);
-        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
-            i++;
-            udelay(5);
-            eecd = E1000_READ_REG(hw, EECD);
-        }
-        if(!(eecd & E1000_EECD_GNT)) {
-            eecd &= ~E1000_EECD_REQ;
-            E1000_WRITE_REG(hw, EECD, eecd);
-            DEBUGOUT("Could not acquire EEPROM grant\n");
-            return -E1000_ERR_EEPROM;
-        }
+    /* A check for invalid values:  offset too large, too many words, and not
+     * enough words.
+     */
+    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+       (words == 0)) {
+        DEBUGOUT("\"words\" parameter out of bounds\n");
+        return -E1000_ERR_EEPROM;
     }
 
     /* Prepare the EEPROM for writing  */
-    e1000_setup_eeprom(hw);
+    if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+        return -E1000_ERR_EEPROM;
 
-    /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command
-     * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM
-     * into write/erase mode. 
-     */
-    e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
-    if(large_eeprom) 
-        e1000_shift_out_ee_bits(hw, 0, 6);
+    if(eeprom->type == e1000_eeprom_microwire)
+        status = e1000_write_eeprom_microwire(hw, offset, words, data);
     else
-        e1000_shift_out_ee_bits(hw, 0, 4);
+        status = e1000_write_eeprom_spi(hw, offset, words, data);
 
-    /* Prepare the EEPROM */
-    e1000_standby_eeprom(hw);
+    /* Done with writing */
+    e1000_release_eeprom(hw);
 
-    /* Send the Write command (3-bit opcode + addr) */
-    e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3);
-    if(large_eeprom) 
-        /* If we have a 256 word EEPROM, there are 8 address bits */
-        e1000_shift_out_ee_bits(hw, offset, 8);
-    else
-        /* If we have a 64 word EEPROM, there are 6 address bits */
-        e1000_shift_out_ee_bits(hw, offset, 6);
+    return status;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in an SPI EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 8 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+e1000_write_eeprom_spi(struct e1000_hw *hw,
+                       uint16_t offset,
+                       uint16_t words,
+                       uint16_t *data)
+{
+    struct e1000_eeprom_info *eeprom = &hw->eeprom;
+    uint16_t widx = 0;
 
-    /* Send the data */
-    e1000_shift_out_ee_bits(hw, data, 16);
+    DEBUGFUNC("e1000_write_eeprom_spi");
 
-    /* Toggle the CS line.  This in effect tells to EEPROM to actually execute 
-     * the command in question.
-     */
-    e1000_standby_eeprom(hw);
+    while (widx < words) {
+        uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI;
 
-    /* Now read DO repeatedly until is high (equal to '1').  The EEEPROM will
-     * signal that the command has been completed by raising the DO signal.
-     * If DO does not go high in 10 milliseconds, then error out.
-     */
-    for(i = 0; i < 200; i++) {
-        eecd = E1000_READ_REG(hw, EECD);
-        if(eecd & E1000_EECD_DO) break;
-        udelay(50);
-    }
-    if(i == 200) {
-        DEBUGOUT("EEPROM Write did not complete\n");
-        status = -E1000_ERR_EEPROM;
+        if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
+
+        e1000_standby_eeprom(hw);
+
+        /*  Send the WRITE ENABLE command (8 bit opcode )  */
+        e1000_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI,
+                                    eeprom->opcode_bits);
+
+        e1000_standby_eeprom(hw);
+
+        /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+        if((eeprom->address_bits == 8) && (offset >= 128))
+            write_opcode |= EEPROM_A8_OPCODE_SPI;
+
+        /* Send the Write command (8-bit opcode + addr) */
+        e1000_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits);
+
+        e1000_shift_out_ee_bits(hw, (uint16_t)((offset + widx)*2),
+                                eeprom->address_bits);
+
+        /* Send the data */
+
+        /* Loop to allow for up to whole page write (32 bytes) of eeprom */
+        while (widx < words) {
+            uint16_t word_out = data[widx];
+            word_out = (word_out >> 8) | (word_out << 8);
+            e1000_shift_out_ee_bits(hw, word_out, 16);
+            widx++;
+
+            /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE
+             * operation, while the smaller eeproms are capable of an 8-byte
+             * PAGE WRITE operation.  Break the inner loop to pass new address
+             */
+            if((((offset + widx)*2) % eeprom->page_size) == 0) {
+                e1000_standby_eeprom(hw);
+                break;
+            }
+        }
     }
 
-    /* Recover from write */
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in a Microwire EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 16 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+e1000_write_eeprom_microwire(struct e1000_hw *hw,
+                             uint16_t offset,
+                             uint16_t words,
+                             uint16_t *data)
+{
+    struct e1000_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd;
+    uint16_t words_written = 0;
+    uint16_t i = 0;
+
+    DEBUGFUNC("e1000_write_eeprom_microwire");
+
+    /* Send the write enable command to the EEPROM (3-bit opcode plus
+     * 6/8-bit dummy address beginning with 11).  It's less work to include
+     * the 11 of the dummy address as part of the opcode than it is to shift
+     * it over the correct number of bits for the address.  This puts the
+     * EEPROM into write/erase mode.
+     */
+    e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE,
+                            (uint16_t)(eeprom->opcode_bits + 2));
+
+    e1000_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+    /* Prepare the EEPROM */
     e1000_standby_eeprom(hw);
 
-    /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command
-     * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM
-     * out of write/erase mode.
-     */
-    e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
-    if(large_eeprom) 
-        e1000_shift_out_ee_bits(hw, 0, 6);
-    else
-        e1000_shift_out_ee_bits(hw, 0, 4);
+    while (words_written < words) {
+        /* Send the Write command (3-bit opcode + addr) */
+        e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE,
+                                eeprom->opcode_bits);
 
-    /* Done with writing */
-    e1000_cleanup_eeprom(hw);
+        e1000_shift_out_ee_bits(hw, (uint16_t)(offset + words_written),
+                                eeprom->address_bits);
 
-    /* Stop requesting EEPROM access */
-    if(hw->mac_type > e1000_82544) {
-        eecd = E1000_READ_REG(hw, EECD);
-        eecd &= ~E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
+        /* Send the data */
+        e1000_shift_out_ee_bits(hw, data[words_written], 16);
+
+        /* Toggle the CS line.  This in effect tells the EEPROM to execute
+         * the previous command.
+         */
+        e1000_standby_eeprom(hw);
+
+        /* Read DO repeatedly until it is high (equal to '1').  The EEPROM will
+         * signal that the command has been completed by raising the DO signal.
+         * If DO does not go high in 10 milliseconds, then error out.
+         */
+        for(i = 0; i < 200; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if(eecd & E1000_EECD_DO) break;
+            udelay(50);
+        }
+        if(i == 200) {
+            DEBUGOUT("EEPROM Write did not complete\n");
+            return -E1000_ERR_EEPROM;
+        }
+
+        /* Recover from write */
+        e1000_standby_eeprom(hw);
+
+        words_written++;
     }
 
-    return status;
+    /* Send the write disable command to the EEPROM (3-bit opcode plus
+     * 6/8-bit dummy address beginning with 10).  It's less work to include
+     * the 10 of the dummy address as part of the opcode than it is to shift
+     * it over the correct number of bits for the address.  This takes the
+     * EEPROM out of write/erase mode.
+     */
+    e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE,
+                            (uint16_t)(eeprom->opcode_bits + 2));
+
+    e1000_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+    return 0;
 }
 
 /******************************************************************************
@@ -2734,7 +3380,7 @@
     DEBUGFUNC("e1000_read_part_num");
 
     /* Get word 0 from EEPROM */
-    if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+    if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -2742,7 +3388,7 @@
     *part_num = (uint32_t) (eeprom_data << 16);
 
     /* Get word 1 from EEPROM */
-    if(e1000_read_eeprom(hw, ++offset, &eeprom_data) < 0) {
+    if(e1000_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -2768,7 +3414,7 @@
 
     for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
         offset = i >> 1;
-        if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+        if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
             DEBUGOUT("EEPROM Read Error\n");
             return -E1000_ERR_EEPROM;
         }
@@ -2790,7 +3436,7 @@
 /******************************************************************************
  * Initializes receive address filters.
  *
- * hw - Struct containing variables accessed by shared code 
+ * hw - Struct containing variables accessed by shared code
  *
  * Places the MAC address in receive address register 0 and clears the rest
  * of the receive addresss registers. Clears the multicast table. Assumes
@@ -2835,7 +3481,7 @@
  *
  * The given list replaces any existing list. Clears the last 15 receive
  * address registers and the multicast table. Uses receive address registers
- * for the first 15 multicast addresses, and hashes the rest into the 
+ * for the first 15 multicast addresses, and hashes the rest into the
  * multicast table.
  *****************************************************************************/
 void
@@ -2884,7 +3530,7 @@
         DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
 
         /* Place this multicast address in the RAR if there is room, *
-         * else put it in the MTA            
+         * else put it in the MTA
          */
         if(rar_used_count < E1000_RAR_ENTRIES) {
             e1000_rar_set(hw,
@@ -2902,7 +3548,7 @@
  * Hashes an address to determine its location in the multicast table
  *
  * hw - Struct containing variables accessed by shared code
- * mc_addr - the multicast address to hash 
+ * mc_addr - the multicast address to hash
  *****************************************************************************/
 uint32_t
 e1000_hash_mc_addr(struct e1000_hw *hw,
@@ -2911,7 +3557,7 @@
     uint32_t hash_value = 0;
 
     /* The portion of the address that is used for the hash table is
-     * determined by the mc_filter_type setting.  
+     * determined by the mc_filter_type setting.
      */
     switch (hw->mc_filter_type) {
     /* [0] [1] [2] [3] [4] [5]
@@ -2954,12 +3600,12 @@
     uint32_t mta;
     uint32_t temp;
 
-    /* The MTA is a register array of 128 32-bit registers.  
-     * It is treated like an array of 4096 bits.  We want to set 
+    /* The MTA is a register array of 128 32-bit registers.
+     * It is treated like an array of 4096 bits.  We want to set
      * bit BitArray[hash_value]. So we figure out what register
      * the bit is in, read it, OR in the new bit, then write
-     * back the new value.  The register is determined by the 
-     * upper 7 bits of the hash value and the bit within that 
+     * back the new value.  The register is determined by the
+     * upper 7 bits of the hash value and the bit within that
      * register are determined by the lower 5 bits of the value.
      */
     hash_reg = (hash_value >> 5) & 0x7F;
@@ -2997,7 +3643,7 @@
     uint32_t rar_low, rar_high;
 
     /* HW expects these in little endian so we reverse the byte order
-     * from network order (big endian) to little endian              
+     * from network order (big endian) to little endian
      */
     rar_low = ((uint32_t) addr[0] |
                ((uint32_t) addr[1] << 8) |
@@ -3055,24 +3701,24 @@
     const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
     uint16_t eeprom_data, i, temp;
     const uint16_t led_mask = 0x0F;
-        
+
     DEBUGFUNC("e1000_id_led_init");
-    
+
     if(hw->mac_type < e1000_82540) {
         /* Nothing to do */
         return 0;
     }
-    
+
     ledctl = E1000_READ_REG(hw, LEDCTL);
     hw->ledctl_default = ledctl;
     hw->ledctl_mode1 = hw->ledctl_default;
     hw->ledctl_mode2 = hw->ledctl_default;
-        
-    if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) {
+
+    if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
-    if((eeprom_data== ID_LED_RESERVED_0000) || 
+    if((eeprom_data== ID_LED_RESERVED_0000) ||
        (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
     for(i = 0; i < 4; i++) {
         temp = (eeprom_data >> (i << 2)) & led_mask;
@@ -3123,9 +3769,9 @@
 e1000_setup_led(struct e1000_hw *hw)
 {
     uint32_t ledctl;
- 
+
     DEBUGFUNC("e1000_setup_led");
-   
+
     switch(hw->device_id) {
     case E1000_DEV_ID_82542:
     case E1000_DEV_ID_82543GC_FIBER:
@@ -3143,7 +3789,7 @@
         hw->ledctl_default = ledctl;
         /* Turn off LED0 */
         ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
-                    E1000_LEDCTL_LED0_BLINK | 
+                    E1000_LEDCTL_LED0_BLINK |
                     E1000_LEDCTL_LED0_MODE_MASK);
         ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
         E1000_WRITE_REG(hw, LEDCTL, ledctl);
@@ -3155,6 +3801,9 @@
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
     case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82547EI:
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
         break;
     default:
@@ -3193,6 +3842,9 @@
     case E1000_DEV_ID_82545EM_FIBER:
     case E1000_DEV_ID_82546EB_COPPER:
     case E1000_DEV_ID_82546EB_FIBER:
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82547EI:
         /* Restore LEDCTL settings */
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
         break;
@@ -3202,7 +3854,7 @@
     }
     return 0;
 }
-    
+
 /******************************************************************************
  * Turns on the software controllable LED
  *
@@ -3244,6 +3896,9 @@
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
     case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82547EI:
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
         break;
     default:
@@ -3294,6 +3949,9 @@
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
     case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82547EI:
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
         break;
     default:
@@ -3304,7 +3962,7 @@
 }
 
 /******************************************************************************
- * Clears all hardware statistics counters. 
+ * Clears all hardware statistics counters.
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
@@ -3423,7 +4081,7 @@
     DEBUGFUNC("e1000_update_adaptive");
 
     if(hw->adaptive_ifs) {
-        if((hw->collision_delta * hw->ifs_ratio) > 
+        if((hw->collision_delta * hw->ifs_ratio) >
            hw->tx_packet_delta) {
             if(hw->tx_packet_delta > MIN_NUM_XMITS) {
                 hw->in_ifs_mode = TRUE;
@@ -3436,7 +4094,7 @@
                 }
             }
         } else {
-            if((hw->in_ifs_mode == TRUE) && 
+            if((hw->in_ifs_mode == TRUE) &&
                (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
                 hw->current_ifs_val = 0;
                 hw->in_ifs_mode = FALSE;
@@ -3450,7 +4108,7 @@
 
 /******************************************************************************
  * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  * frame_len - The length of the frame in question
  * mac_addr - The Ethernet destination address of the frame in question
@@ -3478,16 +4136,16 @@
     carry_bit = 0x80000000 & stats->gorcl;
     stats->gorcl += frame_len;
     /* If the high bit of Gorcl (the low 32 bits of the Good Octets
-     * Received Count) was one before the addition, 
-     * AND it is zero after, then we lost the carry out, 
+     * Received Count) was one before the addition,
+     * AND it is zero after, then we lost the carry out,
      * need to add one to Gorch (Good Octets Received Count High).
-     * This could be simplified if all environments supported 
+     * This could be simplified if all environments supported
      * 64-bit integers.
      */
     if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
         stats->gorch++;
     /* Is this a broadcast or multicast?  Check broadcast first,
-     * since the test for a multicast frame will test positive on 
+     * since the test for a multicast frame will test positive on
      * a broadcast frame.
      */
     if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
@@ -3608,3 +4266,221 @@
     e1000_io_write(hw, io_data, value);
 }
 
+
+/******************************************************************************
+ * Estimates the cable length.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * min_length - The estimated minimum length
+ * max_length - The estimated maximum length
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * This function always returns a ranged length (minimum & maximum).
+ * So for M88 phy's, this function interprets the one value returned from the
+ * register to the minimum and maximum range.
+ * For IGP phy's, the function calculates the range by the AGC registers.
+ *****************************************************************************/
+int32_t
+e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length,
+                       uint16_t *max_length)
+{
+    uint16_t agc_value = 0;
+    uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+    uint16_t i, phy_data;
+
+    DEBUGFUNC("e1000_get_cable_length");
+
+    *min_length = *max_length = 0;
+
+    /* Use old method for Phy older than IGP */
+    if(hw->phy_type == e1000_phy_m88) {
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+
+        /* Convert the enum value to ranged values */
+        switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+               M88E1000_PSSR_CABLE_LENGTH_SHIFT) {
+        case e1000_cable_length_50:
+            *min_length = 0;
+            *max_length = e1000_igp_cable_length_50;
+            break;
+        case e1000_cable_length_50_80:
+            *min_length = e1000_igp_cable_length_50;
+            *max_length = e1000_igp_cable_length_80;
+            break;
+        case e1000_cable_length_80_110:
+            *min_length = e1000_igp_cable_length_80;
+            *max_length = e1000_igp_cable_length_110;
+            break;
+        case e1000_cable_length_110_140:
+            *min_length = e1000_igp_cable_length_110;
+            *max_length = e1000_igp_cable_length_140;
+            break;
+        case e1000_cable_length_140:
+            *min_length = e1000_igp_cable_length_140;
+            *max_length = e1000_igp_cable_length_170;
+            break;
+        default:
+            return -E1000_ERR_PHY;
+            break;
+        }
+    } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
+        uint16_t agc_reg_array[IGP01E1000_PHY_AGC_NUM] = {IGP01E1000_PHY_AGC_A,
+                                                          IGP01E1000_PHY_AGC_B,
+                                                          IGP01E1000_PHY_AGC_C,
+                                                          IGP01E1000_PHY_AGC_D};
+        /* Read the AGC registers for all channels */
+        for(i = 0; i < IGP01E1000_PHY_AGC_NUM; i++) {
+            if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                   agc_reg_array[i]) != E1000_SUCCESS)
+                return -E1000_ERR_PHY;
+            if(e1000_read_phy_reg(hw, agc_reg_array[i] &
+                                  IGP01E1000_PHY_PAGE_SELECT, &phy_data) !=
+                                  E1000_SUCCESS)
+                return -E1000_ERR_PHY;
+
+            cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+
+            /* Array bound check. */
+            if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+               (cur_agc == 0))
+                return -E1000_ERR_PHY;
+
+            agc_value += cur_agc;
+
+            /* Update minimal AGC value. */
+            if(min_agc > cur_agc)
+                min_agc = cur_agc;
+        }
+
+        /* Return to page 0 */
+        if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) !=
+           E1000_SUCCESS)
+            return -E1000_ERR_PHY;
+
+        /* Remove the minimal AGC result for length < 50m */
+        if(agc_value < IGP01E1000_PHY_AGC_NUM * e1000_igp_cable_length_50) {
+            agc_value -= min_agc;
+
+            /* Get the average length of the remaining 3 channels */
+            agc_value /= (IGP01E1000_PHY_AGC_NUM - 1);
+        } else {
+            /* Get the average length of all the 4 channels. */
+            agc_value /= IGP01E1000_PHY_AGC_NUM;
+        }
+
+        /* Set the range of the calculated length. */
+        *min_length = ((e1000_igp_cable_length_table[agc_value] -
+                       IGP01E1000_AGC_RANGE) > 0) ?
+                       (e1000_igp_cable_length_table[agc_value] -
+                       IGP01E1000_AGC_RANGE) : 0;
+        *max_length = e1000_igp_cable_length_table[agc_value] +
+                      IGP01E1000_AGC_RANGE;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check the cable polarity
+ *
+ * hw - Struct containing variables accessed by shared code
+ * polarity - output parameter : 0 - Polarity is not reversed
+ *                               1 - Polarity is reversed.
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * For phy's older then IGP, this function simply reads the polarity bit in the
+ * Phy Status register.  For IGP phy's, this bit is valid only if link speed is
+ * 10 Mbps.  If the link speed is 100 Mbps there is no polarity so this bit will
+ * return 0.  If the link speed is 1000 Mbps the polarity status is in the
+ * IGP01E1000_PHY_PCS_INIT_REG.
+ *****************************************************************************/
+int32_t
+e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity)
+{
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_check_polarity");
+
+    if(hw->phy_type == e1000_phy_m88) {
+        /* return the Polarity bit in the Status register. */
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+        *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+                    M88E1000_PSSR_REV_POLARITY_SHIFT;
+    } else if(hw->phy_type == e1000_phy_igp) {
+        /* Read the Status register to check the speed */
+        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+
+        /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
+         * find the polarity status */
+        if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+           IGP01E1000_PSSR_SPEED_1000MBPS) {
+
+            /* Read the GIG initialization PCS register (0x00B4) */
+            if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                   IGP01E1000_PHY_PCS_INIT_REG) < 0)
+                return -E1000_ERR_PHY;
+
+            if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG &
+                                  IGP01E1000_PHY_PAGE_SELECT, &phy_data) < 0)
+                return -E1000_ERR_PHY;
+
+            /* Return to page 0 */
+            if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) !=
+               E1000_SUCCESS)
+                return -E1000_ERR_PHY;
+
+            /* Check the polarity bits */
+            *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0;
+        } else {
+            /* For 10 Mbps, read the polarity bit in the status register. (for
+             * 100 Mbps this bit is always 0) */
+            *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check if Downshift occured
+ *
+ * hw - Struct containing variables accessed by shared code
+ * downshift - output parameter : 0 - No Downshift ocured.
+ *                                1 - Downshift ocured.
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * For phy's older then IGP, this function reads the Downshift bit in the Phy
+ * Specific Status register.  For IGP phy's, it reads the Downgrade bit in the
+ * Link Health register.  In IGP this bit is latched high, so the driver must
+ * read it immediately after link is established.
+ *****************************************************************************/
+int32_t
+e1000_check_downshift(struct e1000_hw *hw)
+{
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_check_downshift");
+
+    if(hw->phy_type == e1000_phy_igp) {
+        if(e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
+    }
+    else if(hw->phy_type == e1000_phy_m88) {
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
+                                M88E1000_PSSR_DOWNSHIFT_SHIFT;
+    }
+    return E1000_SUCCESS;
+}
+
diff -urN linux-2.5.65-bk1/drivers/net/e1000/e1000_hw.h linux-2.5.65-bk2/drivers/net/e1000/e1000_hw.h
--- linux-2.5.65-bk1/drivers/net/e1000/e1000_hw.h	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/drivers/net/e1000/e1000_hw.h	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -33,6 +33,7 @@
 #ifndef _E1000_HW_H_
 #define _E1000_HW_H_
 
+
 #include "e1000_osdep.h"
 
 /* Forward declarations of structures used by the shared code */
@@ -50,9 +51,18 @@
     e1000_82540,
     e1000_82545,
     e1000_82546,
+    e1000_82541,
+    e1000_82547,
     e1000_num_macs
 } e1000_mac_type;
 
+typedef enum {
+    e1000_eeprom_uninitialized = 0,
+    e1000_eeprom_spi,
+    e1000_eeprom_microwire,
+    e1000_num_eeprom_types
+} e1000_eeprom_type;
+
 /* Media Types */
 typedef enum {
     e1000_media_type_copper = 0,
@@ -111,6 +121,27 @@
 } e1000_cable_length;
 
 typedef enum {
+    e1000_igp_cable_length_10  = 10,
+    e1000_igp_cable_length_20  = 20,
+    e1000_igp_cable_length_30  = 30,
+    e1000_igp_cable_length_40  = 40,
+    e1000_igp_cable_length_50  = 50,
+    e1000_igp_cable_length_60  = 60,
+    e1000_igp_cable_length_70  = 70,
+    e1000_igp_cable_length_80  = 80,
+    e1000_igp_cable_length_90  = 90,
+    e1000_igp_cable_length_100 = 100,
+    e1000_igp_cable_length_110 = 110,
+    e1000_igp_cable_length_120 = 120,
+    e1000_igp_cable_length_130 = 130,
+    e1000_igp_cable_length_140 = 140,
+    e1000_igp_cable_length_150 = 150,
+    e1000_igp_cable_length_160 = 160,
+    e1000_igp_cable_length_170 = 170,
+    e1000_igp_cable_length_180 = 180
+} e1000_igp_cable_length;
+
+typedef enum {
     e1000_10bt_ext_dist_enable_normal = 0,
     e1000_10bt_ext_dist_enable_lower,
     e1000_10bt_ext_dist_enable_undefined = 0xFF
@@ -123,6 +154,12 @@
 } e1000_rev_polarity;
 
 typedef enum {
+    e1000_downshift_normal = 0,
+    e1000_downshift_activated,
+    e1000_downshift_undefined = 0xFF
+} e1000_downshift;
+
+typedef enum {
     e1000_polarity_reversal_enabled = 0,
     e1000_polarity_reversal_disabled,
     e1000_polarity_reversal_undefined = 0xFF
@@ -142,10 +179,17 @@
     e1000_1000t_rx_status_undefined = 0xFF
 } e1000_1000t_rx_status;
 
+typedef enum {
+    e1000_phy_m88 = 0,
+    e1000_phy_igp,
+    e1000_phy_undefined = 0xFF
+} e1000_phy_type;
+
 struct e1000_phy_info {
     e1000_cable_length cable_length;
     e1000_10bt_ext_dist_enable extended_10bt_distance;
     e1000_rev_polarity cable_polarity;
+    e1000_downshift downshift;
     e1000_polarity_reversal polarity_correction;
     e1000_auto_x_mode mdix_mode;
     e1000_1000t_rx_status local_rx;
@@ -157,6 +201,15 @@
     uint32_t receive_errors;
 };
 
+struct e1000_eeprom_info {
+    e1000_eeprom_type type;
+    uint16_t word_size;
+    uint16_t opcode_bits;
+    uint16_t address_bits;
+    uint16_t delay_usec;
+    uint16_t page_size;
+};
+
 
 
 /* Error Codes */
@@ -166,6 +219,7 @@
 #define E1000_ERR_CONFIG   3
 #define E1000_ERR_PARAM    4
 #define E1000_ERR_MAC_TYPE 5
+#define E1000_ERR_PHY_TYPE 6
 
 /* Function prototypes */
 /* Initialization */
@@ -189,13 +243,19 @@
 int32_t e1000_phy_reset(struct e1000_hw *hw);
 int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
 int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length, uint16_t *max_length);
+int32_t e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity);
+int32_t e1000_check_downshift(struct e1000_hw *hw);
 int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
 
 /* EEPROM Functions */
-int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t *data);
+void e1000_init_eeprom_params(struct e1000_hw *hw);
+int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
 int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
 int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw);
-int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t data);
+int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
 int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
 int32_t e1000_read_mac_addr(struct e1000_hw * hw);
 
@@ -231,6 +291,7 @@
 uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset);
 void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value);
 void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+
 #define E1000_READ_REG_IO(a, reg) \
     e1000_read_reg_io((a), E1000_##reg)
 #define E1000_WRITE_REG_IO(a, reg, val) \
@@ -253,7 +314,10 @@
 #define E1000_DEV_ID_82545EM_FIBER       0x1011
 #define E1000_DEV_ID_82546EB_COPPER      0x1010
 #define E1000_DEV_ID_82546EB_FIBER       0x1012
-#define NUM_DEV_IDS 16
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EP             0x1018
+#define E1000_DEV_ID_82547EI             0x1019
+#define NUM_DEV_IDS 19
 
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
@@ -298,7 +362,7 @@
 /* This defines the bits that are set in the Interrupt Mask
  * Set/Read Register.  Each bit is documented below:
  *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error 
+ *   o RXSEQ  = Receive Sequence Error
  */
 #define POLL_IMS_ENABLE_MASK ( \
     E1000_IMS_RXDMT0 |         \
@@ -322,9 +386,9 @@
 /* The number of high/low register pairs in the RAR. The RAR (Receive Address
  * Registers) holds the directed and multicast addresses that we monitor. We
  * reserve one of these spots for our directed address, allowing us room for
- * E1000_RAR_ENTRIES - 1 multicast addresses. 
+ * E1000_RAR_ENTRIES - 1 multicast addresses.
  */
-#define E1000_RAR_ENTRIES 16
+#define E1000_RAR_ENTRIES 15
 
 #define MIN_NUMBER_OF_DESCRIPTORS 8
 #define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
@@ -523,7 +587,7 @@
 /* Register Set. (82543, 82544)
  *
  * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
- * These registers are physically located on the NIC, but are mapped into the 
+ * These registers are physically located on the NIC, but are mapped into the
  * host memory address space.
  *
  * RW - register is both readable and writable
@@ -537,6 +601,7 @@
 #define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
 #define E1000_EERD     0x00014  /* EEPROM Read - RW */
 #define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access Register - RW */
 #define E1000_MDIC     0x00020  /* MDI Control - RW */
 #define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
 #define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
@@ -569,6 +634,11 @@
 #define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
 #define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
 #define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
 #define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
 #define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
 #define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
@@ -664,6 +734,7 @@
 #define E1000_82542_EECD     E1000_EECD
 #define E1000_82542_EERD     E1000_EERD
 #define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_FLA      E1000_FLA
 #define E1000_82542_MDIC     E1000_MDIC
 #define E1000_82542_FCAL     E1000_FCAL
 #define E1000_82542_FCAH     E1000_FCAH
@@ -705,6 +776,9 @@
 #define E1000_82542_RADV     E1000_RADV
 #define E1000_82542_RSRPD    E1000_RSRPD
 #define E1000_82542_TXDMAC   E1000_TXDMAC
+#define E1000_82542_TDFHS    E1000_TDFHS
+#define E1000_82542_TDFTS    E1000_TDFTS
+#define E1000_82542_TDFPC    E1000_TDFPC
 #define E1000_82542_TXDCTL   E1000_TXDCTL
 #define E1000_82542_TADV     E1000_TADV
 #define E1000_82542_TSPMT    E1000_TSPMT
@@ -777,6 +851,8 @@
 #define E1000_82542_WUPL     E1000_WUPL
 #define E1000_82542_WUPM     E1000_WUPM
 #define E1000_82542_FFLT     E1000_FFLT
+#define E1000_82542_TDFH     0x08010
+#define E1000_82542_TDFT     0x08018
 #define E1000_82542_FFMT     E1000_FFMT
 #define E1000_82542_FFVT     E1000_FFVT
 
@@ -846,12 +922,15 @@
 struct e1000_hw {
     uint8_t *hw_addr;
     e1000_mac_type mac_type;
+    e1000_phy_type phy_type;
+    uint32_t phy_init_script;
     e1000_media_type media_type;
     void *back;
     e1000_fc_type fc;
     e1000_bus_speed bus_speed;
     e1000_bus_width bus_width;
     e1000_bus_type bus_type;
+    struct e1000_eeprom_info eeprom;
     uint32_t io_base;
     uint32_t phy_id;
     uint32_t phy_revision;
@@ -891,6 +970,7 @@
     uint8_t mac_addr[NODE_ADDRESS_SIZE];
     uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
     boolean_t disable_polarity_correction;
+    boolean_t speed_downgraded;
     boolean_t get_link_status;
     boolean_t tbi_compatibility_en;
     boolean_t tbi_compatibility_on;
@@ -967,14 +1047,20 @@
 #define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
 #define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
 #define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
-#define E1000_EECD_FWE_MASK  0x00000030 
+#define E1000_EECD_FWE_MASK  0x00000030
 #define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
 #define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
 #define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
 #define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
 #define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
 #define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+					 * (0-small, 1-large) */
+#define E1000_EECD_TYPE      0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
 
 /* EEPROM Read */
 #define E1000_EERD_START      0x00000001 /* Start Read */
@@ -984,8 +1070,15 @@
 #define E1000_EERD_DATA_SHIFT 16
 #define E1000_EERD_DATA_MASK  0xFFFF0000 /* Read Data */
 
+/* SPI EEPROM Status Register */
+#define EEPROM_STATUS_RDY_SPI  0x01
+#define EEPROM_STATUS_WEN_SPI  0x02
+#define EEPROM_STATUS_BP0_SPI  0x04
+#define EEPROM_STATUS_BP1_SPI  0x08
+#define EEPROM_STATUS_WPEN_SPI 0x80
+
 /* Extended Device Control */
-#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */ 
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
 #define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
 #define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
 #define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
@@ -1239,6 +1332,7 @@
 #define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
 #define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
 #define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
 
 /* Wake Up Filter Control */
 #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
@@ -1282,7 +1376,7 @@
 #define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
 #define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
 #define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery 
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
                                              * Filtering */
 #define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
 #define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
@@ -1302,18 +1396,40 @@
 
 #define E1000_MDALIGN          4096
 
-/* EEPROM Commands */
-#define EEPROM_READ_OPCODE  0x6  /* EERPOM read opcode */
-#define EEPROM_WRITE_OPCODE 0x5  /* EERPOM write opcode */
-#define EEPROM_ERASE_OPCODE 0x7  /* EERPOM erase opcode */
-#define EEPROM_EWEN_OPCODE  0x13 /* EERPOM erase/write enable */
-#define EEPROM_EWDS_OPCODE  0x10 /* EERPOM erast/write disable */
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7  /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE  0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE  0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Commands - SPI */
+#define EEPROM_MAX_RETRY_SPI    5000 /* Max wait of 5ms, for RDY signal */
+#define EEPROM_READ_OPCODE_SPI  0x3  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI 0x2  /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI    0x8  /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI  0x6  /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI  0x4  /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI  0x5  /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI  0x1  /* EEPROM write Status register */
+
+/* EEPROM Size definitions */
+#define EEPROM_SIZE_16KB        0x1800
+#define EEPROM_SIZE_8KB         0x1400
+#define EEPROM_SIZE_4KB         0x1000
+#define EEPROM_SIZE_2KB         0x0C00
+#define EEPROM_SIZE_1KB         0x0800
+#define EEPROM_SIZE_512B        0x0400
+#define EEPROM_SIZE_128B        0x0000
+#define EEPROM_SIZE_MASK        0x1C00
+
 
 /* EEPROM Word Offsets */
 #define EEPROM_COMPAT              0x0003
 #define EEPROM_ID_LED_SETTINGS     0x0004
 #define EEPROM_INIT_CONTROL1_REG   0x000A
 #define EEPROM_INIT_CONTROL2_REG   0x000F
+#define EEPROM_CFG                 0x0012
 #define EEPROM_FLASH_VERSION       0x0032
 #define EEPROM_CHECKSUM_REG        0x003F
 
@@ -1334,9 +1450,10 @@
 #define ID_LED_OFF1_ON2      0x8
 #define ID_LED_OFF1_OFF2     0x9
 
-/* Mask bits for fields in Word 0x03 of the EEPROM */
-#define EEPROM_COMPAT_SERVER 0x0400
-#define EEPROM_COMPAT_CLIENT 0x0200
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
 
 /* Mask bits for fields in Word 0x0a of the EEPROM */
 #define EEPROM_WORD0A_ILOS   0x0010
@@ -1409,7 +1526,9 @@
 
 /* PBA constants */
 #define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+#define E1000_PBA_22K 0x0016
 #define E1000_PBA_24K 0x0018
+#define E1000_PBA_30K 0x001E
 #define E1000_PBA_40K 0x0028
 #define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
 
@@ -1438,26 +1557,26 @@
 
 /* The number of bits that we need to shift right to move the "pause"
  * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
- * in the TXCW register 
+ * in the TXCW register
  */
 #define PAUSE_SHIFT 5
 
 /* The number of bits that we need to shift left to move the "SWDPIO"
  * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
- * in the CTRL register 
+ * in the CTRL register
  */
 #define SWDPIO_SHIFT 17
 
 /* The number of bits that we need to shift left to move the "SWDPIO_EXT"
  * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
  * Extended CTRL register.
- * in the CTRL register 
+ * in the CTRL register
  */
 #define SWDPIO__EXT_SHIFT 4
 
 /* The number of bits that we need to shift left to move the "ILOS"
  * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
- * in the CTRL register 
+ * in the CTRL register
  */
 #define ILOS_SHIFT  3
 
@@ -1475,7 +1594,7 @@
 /* TBI_ACCEPT macro definition:
  *
  * This macro requires:
- *      adapter = a pointer to struct e1000_hw 
+ *      adapter = a pointer to struct e1000_hw
  *      status = the 8 bit status field of the RX descriptor with EOP set
  *      error = the 8 bit error field of the RX descriptor with EOP set
  *      length = the sum of all the length fields of the RX descriptors that
@@ -1484,7 +1603,7 @@
  *      max_frame_length = the maximum frame length we want to accept.
  *      min_frame_length = the minimum frame length we want to accept.
  *
- * This macro is a conditional that should be used in the interrupt 
+ * This macro is a conditional that should be used in the interrupt
  * handler's Rx processing routine when RxErrors have been detected.
  *
  * Typical use:
@@ -1547,6 +1666,29 @@
 #define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
 #define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
 
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */
+#define IGP01E1000_PHY_PORT_CTRL   0x12 /* PHY Specific Control Register */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
+#define IGP01E1000_GMII_FIFO       0x14 /* GMII FIFO Register */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP01E1000_PHY_PAGE_SELECT     0x1F /* PHY Page Select Core Register */
+
+/* IGP01E1000 AGC Registers - stores the cable length values*/
+#define IGP01E1000_PHY_AGC_A        0x1172
+#define IGP01E1000_PHY_AGC_B        0x1272
+#define IGP01E1000_PHY_AGC_C        0x1472
+#define IGP01E1000_PHY_AGC_D        0x1872
+
+/* Number of AGC registers */
+#define IGP01E1000_PHY_AGC_NUM     4
+
+/* IGP01E1000 PCS Initialization register - stores the polarity status when
+ * speed = 1000 Mbps. */
+#define IGP01E1000_PHY_PCS_INIT_REG  0x00B4
+
+
 #define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
 
 /* PHY Control Register */
@@ -1608,7 +1750,7 @@
 #define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
 #define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
 #define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
-#define NWAY_ER_PAR_DETECT_FAULT  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
 
 /* Next Page TX Register */
 #define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
@@ -1619,7 +1761,7 @@
                                     * 0 = cannot comply with msg
                                     */
 #define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */
-#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow 
+#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow
                                     * 0 = sending last NP
                                     */
 
@@ -1628,13 +1770,13 @@
 #define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges
                                        * of different NP
                                        */
-#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg 
+#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg
                                        * 0 = cannot comply with msg
                                        */
 #define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */
 #define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */
 #define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow
-                                        * 0 = sending last NP 
+                                        * 0 = sending last NP
                                         */
 
 /* 1000BASE-T Control Register */
@@ -1681,20 +1823,20 @@
 #define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
 #define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
 #define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
-#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low, 
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low,
                                                 * 0=CLK125 toggling
                                                 */
 #define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
                                                /* Manual MDI configuration */
 #define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
 #define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
-                                                *  100BASE-TX/10BASE-T: 
+                                                *  100BASE-TX/10BASE-T:
                                                 *  MDI Mode
                                                 */
-#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled 
-                                                * all speeds. 
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled
+                                                * all speeds.
                                                 */
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
                                         /* 1=Enable Extended 10BASE-T distance
                                          * (Lower 10BASE-T RX Threshold)
                                          * 0=Normal 10BASE-T RX Threshold */
@@ -1712,6 +1854,7 @@
 /* M88E1000 PHY Specific Status Register */
 #define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
 #define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
 #define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
 #define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
                                             * 3=110-140M;4=>140M */
@@ -1725,6 +1868,7 @@
 #define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
 
 #define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_DOWNSHIFT_SHIFT    5
 #define M88E1000_PSSR_MDIX_SHIFT         6
 #define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
 
@@ -1733,12 +1877,12 @@
 #define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000 /* 1=Lost lock detect enabled.
                                               * Will assert lost lock and bring
                                               * link down if idle not seen
-                                              * within 1ms in 1000BASE-T 
+                                              * within 1ms in 1000BASE-T
                                               */
 /* Number of times we will attempt to autonegotiate before downshifting if we
  * are the master */
 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000    
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
@@ -1753,10 +1897,93 @@
 #define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
 #define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
 
+
+/* IGP01E1000 Specific Port Config Register - R/W */
+#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT  0x0010
+#define IGP01E1000_PSCFR_PRE_EN                0x0020
+#define IGP01E1000_PSCFR_SMART_SPEED           0x0080
+#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK    0x0100
+#define IGP01E1000_PSCFR_DISABLE_JABBER        0x0400
+#define IGP01E1000_PSCFR_DISABLE_TRANSMIT      0x2000
+
+/* IGP01E1000 Specific Port Status Register - R/O */
+#define IGP01E1000_PSSR_AUTONEG_FAILED         0x0001 /* RO LH SC */
+#define IGP01E1000_PSSR_POLARITY_REVERSED      0x0002
+#define IGP01E1000_PSSR_CABLE_LENGTH           0x007C
+#define IGP01E1000_PSSR_FULL_DUPLEX            0x0200
+#define IGP01E1000_PSSR_LINK_UP                0x0400
+#define IGP01E1000_PSSR_MDIX                   0x0800
+#define IGP01E1000_PSSR_SPEED_MASK             0xC000 /* speed bits mask */
+#define IGP01E1000_PSSR_SPEED_10MBPS           0x4000
+#define IGP01E1000_PSSR_SPEED_100MBPS          0x8000
+#define IGP01E1000_PSSR_SPEED_1000MBPS         0xC000
+#define IGP01E1000_PSSR_CABLE_LENGTH_SHIFT     0x0002 /* shift right 2 */
+#define IGP01E1000_PSSR_MDIX_SHIFT             0x000B /* shift right 11 */
+
+/* IGP01E1000 Specific Port Control Register - R/W */
+#define IGP01E1000_PSCR_TP_LOOPBACK            0x0001
+#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR      0x0200
+#define IGP01E1000_PSCR_TEN_CRS_SELECT         0x0400
+#define IGP01E1000_PSCR_FLIP_CHIP              0x0800
+#define IGP01E1000_PSCR_AUTO_MDIX              0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX         0x2000 /* 0-MDI, 1-MDIX */
+
+/* IGP01E1000 Specific Port Link Health Register */
+#define IGP01E1000_PLHR_SS_DOWNGRADE           0x8000
+#define IGP01E1000_PLHR_GIG_SCRAMBLER_ERROR    0x4000
+#define IGP01E1000_PLHR_GIG_REM_RCVR_NOK       0x0800 /* LH */
+#define IGP01E1000_PLHR_IDLE_ERROR_CNT_OFLOW   0x0400 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_1             0x0200 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_0             0x0100
+#define IGP01E1000_PLHR_AUTONEG_FAULT          0x0010
+#define IGP01E1000_PLHR_AUTONEG_ACTIVE         0x0008
+#define IGP01E1000_PLHR_VALID_CHANNEL_D        0x0004
+#define IGP01E1000_PLHR_VALID_CHANNEL_C        0x0002
+#define IGP01E1000_PLHR_VALID_CHANNEL_B        0x0001
+#define IGP01E1000_PLHR_VALID_CHANNEL_A        0x0000
+
+/* IGP01E1000 Channel Quality Register */
+#define IGP01E1000_MSE_CHANNEL_D        0x000F
+#define IGP01E1000_MSE_CHANNEL_C        0x00F0
+#define IGP01E1000_MSE_CHANNEL_B        0x0F00
+#define IGP01E1000_MSE_CHANNEL_A        0xF000
+
+/* IGP01E1000 AGC Registers */
+
+#define IGP01E1000_AGC_LENGTH_SHIFT 7         /* Coarse - 13:11, Fine - 10:7 */
+
+/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
+#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
+
+/* The precision of the length is +/- 10 meters */
+#define IGP01E1000_AGC_RANGE    10
+
+/* IGP cable length table */
+static const
+uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
+    { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
+      25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
+      90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+      100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
+
+/* IGP01E1000 PCS Initialization register */
+/* bits 3:6 in the PCS registers stores the channels polarity */
+#define IGP01E1000_PHY_POLARITY_MASK    0x0078
+
+/* IGP01E1000 GMII FIFO Register */
+#define IGP01E1000_GMII_FLEX_SPD               0x10 /* Enable flexible speed
+                                                     * on Link-Up */
+#define IGP01E1000_GMII_SPD                    0x20 /* Enable SPD */
+
 /* Bit definitions for valid PHY IDs. */
 #define M88E1000_E_PHY_ID  0x01410C50
 #define M88E1000_I_PHY_ID  0x01410C30
 #define M88E1011_I_PHY_ID  0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
 #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
 #define M88E1011_I_REV_4   0x04
diff -urN linux-2.5.65-bk1/drivers/net/e1000/e1000_main.c linux-2.5.65-bk2/drivers/net/e1000/e1000_main.c
--- linux-2.5.65-bk1/drivers/net/e1000/e1000_main.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/drivers/net/e1000/e1000_main.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -30,7 +30,22 @@
 
 /* Change Log
  *
- * 4.4.19       11/27/02
+ * 5.0.43	3/5/03
+ *   o Feature: Added support for 82541 and 82547 hardware.
+ *   o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of
+ *   eeproms.
+ *   o Feature: Added support for TCP Segmentation Offload (TSO).
+ *   o Feature: Added MII ioctl.
+ *   o Feature: Added support for statistics reporting through ethtool.
+ *   o Cleanup: Removed proprietary hooks for ANS.
+ *   o Cleanup: Miscellaneous code changes to improve CPU utilization.
+ *   	- Replaced "%" with conditionals and "+-" operators.
+ *   	- Implemented dynamic Interrupt Throttle Rate (ITR).
+ *   	- Reduced expensive PCI reads of ICR in interrupt.
+ *   o Bug fix: Request IRQ after descriptor ring setup to avoid panic in
+ *   shared interrupt instances.
+ *
+ * 4.4.18       11/27/02
  *   o Feature: Added user-settable knob for interrupt throttle rate (ITR).
  *   o Cleanup: removed large static array allocations.
  *   o Cleanup: C99 struct initializer format.
@@ -42,25 +57,12 @@
  *   o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool.
  * 
  * 4.4.12       10/15/02
- *   o Clean up: use members of pci_device rather than direct calls to
- *     pci_read_config_word.
- *   o Bug fix: changed default flow control settings.
- *   o Clean up: ethtool file now has an inclusive list for adapters in the
- *     Wake-On-LAN capabilities instead of an exclusive list.
- *   o Bug fix: miscellaneous WoL bug fixes.
- *   o Added software interrupt for clearing rx ring
- *   o Bug fix: easier to undo "forcing" of 1000/fd using ethtool.
- *   o Now setting netdev->mem_end in e1000_probe.
- *   o Clean up: Moved tx_timeout from interrupt context to process context
- *     using schedule_task.
- * 
- * 4.3.15       8/9/02
  */
 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "4.4.19-k3";
-char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
+char e1000_driver_version[] = "5.0.43-k1";
+char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
  *
@@ -104,6 +106,8 @@
 	{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	/* required last entry */
 	{0,}
 };
@@ -112,7 +116,7 @@
 
 static char *e1000_strings[] = {
 	"Intel(R) PRO/1000 Network Connection",
-	"Compaq Gigabit Ethernet Server Adapter",
+	"HP Gigabit Ethernet Server Adapter",
 	"IBM Mobile, Desktop & Server Adapters"
 };
 
@@ -121,6 +125,7 @@
 int e1000_up(struct e1000_adapter *adapter);
 void e1000_down(struct e1000_adapter *adapter);
 void e1000_reset(struct e1000_adapter *adapter);
+int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
 
 static int e1000_init_module(void);
 static void e1000_exit_module(void);
@@ -141,6 +146,7 @@
 static void e1000_set_multi(struct net_device *netdev);
 static void e1000_update_phy_info(unsigned long data);
 static void e1000_watchdog(unsigned long data);
+static void e1000_82547_tx_fifo_stall(unsigned long data);
 static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
 static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
@@ -149,14 +155,18 @@
 static inline void e1000_irq_disable(struct e1000_adapter *adapter);
 static inline void e1000_irq_enable(struct e1000_adapter *adapter);
 static void e1000_intr(int irq, void *data, struct pt_regs *regs);
-static void e1000_clean_tx_irq(struct e1000_adapter *adapter);
 #ifdef CONFIG_E1000_NAPI
-static int e1000_poll(struct net_device *netdev, int *budget);
+static int e1000_clean(struct net_device *netdev, int *budget);
+static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
+                                    int *work_done, int work_to_do);
 #else
-static void e1000_clean_rx_irq(struct e1000_adapter *adapter);
+static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter);
 #endif
+static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter);
 static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
 static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
+			   int cmd);
 static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
 static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
 static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
@@ -164,6 +174,9 @@
                                      struct sk_buff *skb);
 static void e1000_tx_timeout(struct net_device *dev);
 static void e1000_tx_timeout_task(struct net_device *dev);
+static void e1000_smartspeed(struct e1000_adapter *adapter);
+static inline int e1000_82547_fifo_workaround(struct e1000_adapter *adapter,
+					      struct sk_buff *skb);
 
 static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
 static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
@@ -182,6 +195,7 @@
 	.priority	= 0
 };
 
+
 /* Exported from other modules */
 
 extern void e1000_check_options(struct e1000_adapter *adapter);
@@ -249,13 +263,10 @@
 {
 	struct net_device *netdev = adapter->netdev;
 
-	if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM,
-	               netdev->name, netdev))
-		return -1;
-
 	/* hardware has been reset, we need to reload some things */
 
 	e1000_set_multi(netdev);
+
 	e1000_restore_vlan(adapter);
 
 	e1000_configure_tx(adapter);
@@ -263,6 +274,14 @@
 	e1000_configure_rx(adapter);
 	e1000_alloc_rx_buffers(adapter);
 
+	if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM,
+		       netdev->name, netdev)) {
+		e1000_reset_hw(&adapter->hw);
+		e1000_free_tx_resources(adapter);
+		e1000_free_rx_resources(adapter);
+		return -1;
+	}
+
 	mod_timer(&adapter->watchdog_timer, jiffies);
 	e1000_irq_enable(adapter);
 
@@ -276,6 +295,7 @@
 
 	e1000_irq_disable(adapter);
 	free_irq(netdev->irq, netdev);
+	del_timer_sync(&adapter->tx_fifo_stall_timer);
 	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
 	adapter->link_speed = 0;
@@ -291,14 +311,28 @@
 void
 e1000_reset(struct e1000_adapter *adapter)
 {
+	uint32_t pba;
 	/* Repartition Pba for greater than 9k mtu
 	 * To take effect CTRL.RST is required.
 	 */
 
-	if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
-		E1000_WRITE_REG(&adapter->hw, PBA, E1000_JUMBO_PBA);
-	else
-		E1000_WRITE_REG(&adapter->hw, PBA, E1000_DEFAULT_PBA);
+	if(adapter->hw.mac_type < e1000_82547) {
+		if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
+			pba = E1000_PBA_40K;
+		else
+			pba = E1000_PBA_48K;
+	} else {
+		if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
+			pba = E1000_PBA_22K;
+		else
+			pba = E1000_PBA_30K;
+		adapter->tx_fifo_head = 0;
+		adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT;
+		adapter->tx_fifo_size =
+			(E1000_PBA_40K - pba) << E1000_TX_FIFO_SIZE_SHIFT;
+		atomic_set(&adapter->tx_fifo_stall, 0);
+	}
+	E1000_WRITE_REG(&adapter->hw, PBA, pba);
 
 	adapter->hw.fc = adapter->hw.original_fc;
 	e1000_reset_hw(&adapter->hw);
@@ -389,9 +423,9 @@
 	netdev->change_mtu = &e1000_change_mtu;
 	netdev->do_ioctl = &e1000_ioctl;
 	netdev->tx_timeout = &e1000_tx_timeout;
-	netdev->watchdog_timeo = HZ;
+	netdev->watchdog_timeo = 5 * HZ;
 #ifdef CONFIG_E1000_NAPI
-	netdev->poll = &e1000_poll;
+	netdev->poll = &e1000_clean;
 	netdev->weight = 64;
 #endif
 	netdev->vlan_rx_register = e1000_vlan_rx_register;
@@ -413,17 +447,18 @@
 
 	if(adapter->hw.mac_type >= e1000_82543) {
 		netdev->features = NETIF_F_SG |
-			           NETIF_F_HW_CSUM |
-		       	           NETIF_F_HW_VLAN_TX |
-		                   NETIF_F_HW_VLAN_RX |
+				   NETIF_F_HW_CSUM |
+				   NETIF_F_HW_VLAN_TX |
+				   NETIF_F_HW_VLAN_RX |
 				   NETIF_F_HW_VLAN_FILTER;
 	} else {
 		netdev->features = NETIF_F_SG;
 	}
 
-	if(adapter->hw.mac_type >= e1000_82544)
+	if((adapter->hw.mac_type >= e1000_82544) &&
+	   (adapter->hw.mac_type != e1000_82547))
 		netdev->features |= NETIF_F_TSO;
- 
+
 	if(pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
@@ -446,13 +481,9 @@
 
 	e1000_get_bus_info(&adapter->hw);
 
-	if((adapter->hw.mac_type == e1000_82544) &&
-	   (adapter->hw.bus_type == e1000_bus_type_pcix))
-
-		adapter->max_data_per_txd = 4096;
-	else
-		adapter->max_data_per_txd = MAX_JUMBO_FRAME_SIZE;
-
+	init_timer(&adapter->tx_fifo_stall_timer);
+	adapter->tx_fifo_stall_timer.function = &e1000_82547_tx_fifo_stall;
+	adapter->tx_fifo_stall_timer.data = (unsigned long) adapter;
 
 	init_timer(&adapter->watchdog_timer);
 	adapter->watchdog_timer.function = &e1000_watchdog;
@@ -482,11 +513,12 @@
 	 * enable the ACPI Magic Packet filter
 	 */
 
-	e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data);
+	e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG,1, &eeprom_data);
 	if((adapter->hw.mac_type >= e1000_82544) &&
 	   (eeprom_data & E1000_EEPROM_APME))
 		adapter->wol |= E1000_WUFC_MAG;
 
+
 	/* reset the hardware with the new settings */
 
 	e1000_reset(adapter);
@@ -533,6 +565,7 @@
 
 	e1000_phy_hw_reset(&adapter->hw);
 
+
 	iounmap(adapter->hw.hw_addr);
 	pci_release_regions(pdev);
 
@@ -568,7 +601,7 @@
 
 	adapter->rx_buffer_len = E1000_RXBUFFER_2048;
 	hw->max_frame_size = netdev->mtu +
-	                         ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+			     ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 	hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
 
 	/* identify the MAC */
@@ -578,6 +611,10 @@
 		return -1;
 	}
 
+	/* initialize eeprom parameters */
+
+	e1000_init_eeprom_params(hw);
+
 	/* flow control settings */
 
 	hw->fc_high_water = E1000_FC_HIGH_THRESH;
@@ -585,6 +622,9 @@
 	hw->fc_pause_time = E1000_FC_PAUSE_TIME;
 	hw->fc_send_xon = 1;
 
+	if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547))
+		hw->phy_init_script = 1;
+
 	/* Media type - copper or fiber */
 
 	if(hw->mac_type >= e1000_82543) {
@@ -782,7 +822,7 @@
 
 	tctl &= ~E1000_TCTL_CT;
 	tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
-	       (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
 
 	E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
 
@@ -852,8 +892,8 @@
 	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
 
 	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
-	        E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
-	        (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+		(adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
 
 	if(adapter->hw.tbi_compatibility_on == 1)
 		rctl |= E1000_RCTL_SBP;
@@ -907,12 +947,9 @@
 
 	if(adapter->hw.mac_type >= e1000_82540) {
 		E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay);
-
-		/* Set the interrupt throttling rate.  Value is calculated
-		 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
-#define MAX_INTS_PER_SEC        8000
-#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
-		E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
+		if(adapter->itr > 1)
+			E1000_WRITE_REG(&adapter->hw, ITR,
+				1000000000 / (adapter->itr * 256));
 	}
 
 	/* Setup the Base and Length of the Rx Descriptor Ring */
@@ -1184,9 +1221,9 @@
 	if(hw->mac_type == e1000_82542_rev2_0)
 		e1000_enter_82542_rst(adapter);
 
-	/* load the first 15 multicast address into the exact filters 1-15
+	/* load the first 14 multicast address into the exact filters 1-14
 	 * RAR 0 is used for the station MAC adddress
-	 * if there are not 15 addresses, go ahead and clear the filters
+	 * if there are not 14 addresses, go ahead and clear the filters
 	 */
 	mc_ptr = netdev->mc_list;
 
@@ -1216,6 +1253,40 @@
 		e1000_leave_82542_rst(adapter);
 }
 
+static void
+e1000_tx_flush(struct e1000_adapter *adapter)
+{
+	uint32_t ctrl, tctl, txcw, icr;
+
+	e1000_irq_disable(adapter);
+
+	if(adapter->hw.mac_type < e1000_82543) {
+		/* Transmit Unit Reset */
+		tctl = E1000_READ_REG(&adapter->hw, TCTL);
+		E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST);
+		E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+		e1000_clean_tx_ring(adapter);
+		e1000_configure_tx(adapter);
+	} else {
+		txcw = E1000_READ_REG(&adapter->hw, TXCW);
+		E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE);
+
+		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU |
+				E1000_CTRL_ILOS);
+
+		mdelay(10);
+
+		e1000_clean_tx_irq(adapter);
+		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+		E1000_WRITE_REG(&adapter->hw, TXCW, txcw);
+
+		/* clear the link status change interrupts this caused */
+		icr = E1000_READ_REG(&adapter->hw, ICR);
+	}
+
+	e1000_irq_enable(adapter);
+}
 
 /* need to wait a few seconds after link up to get diagnostic information from the phy */
 
@@ -1227,6 +1298,48 @@
 }
 
 /**
+ * e1000_82547_tx_fifo_stall - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+
+static void
+e1000_82547_tx_fifo_stall(unsigned long data)
+{
+	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+	struct net_device *netdev = adapter->netdev;
+	uint32_t tctl;
+
+	if(atomic_read(&adapter->tx_fifo_stall)) {
+		if((E1000_READ_REG(&adapter->hw, TDT) ==
+		    E1000_READ_REG(&adapter->hw, TDH)) &&
+		   (E1000_READ_REG(&adapter->hw, TDFT) ==
+		    E1000_READ_REG(&adapter->hw, TDFH)) &&
+		   (E1000_READ_REG(&adapter->hw, TDFTS) ==
+		    E1000_READ_REG(&adapter->hw, TDFHS))) {
+			tctl = E1000_READ_REG(&adapter->hw, TCTL);
+			E1000_WRITE_REG(&adapter->hw, TCTL,
+					tctl & ~E1000_TCTL_EN);
+			E1000_WRITE_REG(&adapter->hw, TDFT,
+					adapter->tx_head_addr);
+			E1000_WRITE_REG(&adapter->hw, TDFH,
+					adapter->tx_head_addr);
+			E1000_WRITE_REG(&adapter->hw, TDFTS,
+					adapter->tx_head_addr);
+			E1000_WRITE_REG(&adapter->hw, TDFHS,
+					adapter->tx_head_addr);
+			E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+			E1000_WRITE_FLUSH(&adapter->hw);
+
+			adapter->tx_fifo_head = 0;
+			atomic_set(&adapter->tx_fifo_stall, 0);
+			netif_wake_queue(netdev);
+		} else {
+			mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1);
+		}
+	}
+}
+
+/**
  * e1000_watchdog - Timer Call-back
  * @data: pointer to netdev cast into an unsigned long
  **/
@@ -1256,6 +1369,7 @@
 			netif_carrier_on(netdev);
 			netif_wake_queue(netdev);
 			mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+			adapter->smartspeed = 0;
 		}
 	} else {
 		if(netif_carrier_ok(netdev)) {
@@ -1268,11 +1382,34 @@
 			netif_stop_queue(netdev);
 			mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
 		}
+
+		e1000_smartspeed(adapter);
 	}
 
 	e1000_update_stats(adapter);
 	e1000_update_adaptive(&adapter->hw);
 
+	if(!netif_carrier_ok(netdev)) {
+		if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) {
+			unsigned long flags;
+			spin_lock_irqsave(&netdev->xmit_lock, flags);
+			e1000_tx_flush(adapter);
+			spin_unlock_irqrestore(&netdev->xmit_lock, flags);
+		}
+	}
+
+	/* Dynamic mode for Interrupt Throttle Rate (ITR) */
+	if(adapter->hw.mac_type >= e1000_82540 && adapter->itr == 1) {
+		/* Symmetric Tx/Rx gets a reduced ITR=2000; Total
+		 * asymmetrical Tx or Rx gets ITR=8000; everyone
+		 * else is between 2000-8000. */
+		uint32_t goc = (adapter->gotcl + adapter->gorcl) / 10000;
+		uint32_t dif = (adapter->gotcl > adapter->gorcl ? 
+			adapter->gotcl - adapter->gorcl :
+			adapter->gorcl - adapter->gotcl) / 10000;
+		uint32_t itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000;
+		E1000_WRITE_REG(&adapter->hw, ITR, 1000000000 / (itr * 256));
+	}
 
 	/* Cause software interrupt to ensure rx ring is cleaned */
 	E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0);
@@ -1301,7 +1438,7 @@
 	int i;
 	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
 	uint16_t ipcse, tucse, mss;
-	
+
 	if(skb_shinfo(skb)->tso_size) {
 		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
 		mss = skb_shinfo(skb)->tso_size;
@@ -1321,7 +1458,7 @@
 
 		i = adapter->tx_ring.next_to_use;
 		context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
-		
+
 		context_desc->lower_setup.ip_fields.ipcss  = ipcss;
 		context_desc->lower_setup.ip_fields.ipcso  = ipcso;
 		context_desc->lower_setup.ip_fields.ipcse  = cpu_to_le16(ipcse);
@@ -1335,12 +1472,12 @@
 			E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP |
 			(skb->len - (hdr_len)));
 
-		i = (i + 1) % adapter->tx_ring.count;
+		if(++i == adapter->tx_ring.count) i = 0;
 		adapter->tx_ring.next_to_use = i;
 
 		return TRUE;
 	}
-	
+
 	return FALSE;
 }
 
@@ -1365,7 +1502,7 @@
 		context_desc->cmd_and_length =
 			cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
 
-		i = (i + 1) % adapter->tx_ring.count;
+		if(++i == adapter->tx_ring.count) i = 0;
 		adapter->tx_ring.next_to_use = i;
 
 		return TRUE;
@@ -1374,24 +1511,24 @@
 	return FALSE;
 }
 
+#define E1000_MAX_TXD_PWR	12
+#define E1000_MAX_DATA_PER_TXD	(1<<E1000_MAX_TXD_PWR)
+
 static inline int
 e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
 {
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
-	int len, offset, size, count, i;
+	int len = skb->len, offset = 0, size, count = 0, i;
+
 	int tso = skb_shinfo(skb)->tso_size;
 	int nr_frags = skb_shinfo(skb)->nr_frags;
-
 	int f;
-	len = skb->len - skb->data_len;
-	i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count;
-	count = 0;
+	len -= skb->data_len;
 
-	offset = 0;
+	i = tx_ring->next_to_use;
 
 	while(len) {
-		i = (i + 1) % tx_ring->count;
-		size = min(len, adapter->max_data_per_txd);
+		size = min(len, E1000_MAX_DATA_PER_TXD);
 		/* Workaround for premature desc write-backs
 		 * in TSO mode.  Append 4-byte sentinel desc */
 		if(tso && !nr_frags && size == len && size > 4)
@@ -1407,6 +1544,7 @@
 		len -= size;
 		offset += size;
 		count++;
+		if(++i == tx_ring->count) i = 0;
 	}
 
 	for(f = 0; f < nr_frags; f++) {
@@ -1417,8 +1555,7 @@
 		offset = 0;
 
 		while(len) {
-			i = (i + 1) % tx_ring->count;
-			size = min(len, adapter->max_data_per_txd);
+			size = min(len, E1000_MAX_DATA_PER_TXD);
 			/* Workaround for premature desc write-backs
 			 * in TSO mode.  Append 4-byte sentinel desc */
 			if(tso && f == (nr_frags-1) && size == len && size > 4)
@@ -1435,8 +1572,10 @@
 			len -= size;
 			offset += size;
 			count++;
+			if(++i == tx_ring->count) i = 0;
 		}
 	}
+	if(--i < 0) i = tx_ring->count - 1;
 	tx_ring->buffer_info[i].skb = skb;
 
 	return count;
@@ -1477,7 +1616,7 @@
 		tx_desc->lower.data =
 			cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length);
 		tx_desc->upper.data = cpu_to_le32(txd_upper);
-		i = (i + 1) % tx_ring->count;
+		if(++i == tx_ring->count) i = 0;
 	}
 
 	tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
@@ -1492,34 +1631,74 @@
 	E1000_WRITE_REG(&adapter->hw, TDT, i);
 }
 
-#define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0))
+/**
+ * 82547 workaround to avoid controller hang in half-duplex environment.
+ * The workaround is to avoid queuing a large packet that would span
+ * the internal Tx FIFO ring boundary by notifying the stack to resend
+ * the packet at a later time.  This gives the Tx FIFO an opportunity to
+ * flush all packets.  When that occurs, we reset the Tx FIFO pointers
+ * to the beginning of the Tx FIFO.
+ **/
+
+#define E1000_FIFO_HDR			0x10
+#define E1000_82547_PAD_LEN		0x3E0
+
+static inline int
+e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+	uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
+	uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR;
+
+	E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR);
+
+	if(adapter->link_duplex != HALF_DUPLEX)
+		goto no_fifo_stall_required;
+
+	if(atomic_read(&adapter->tx_fifo_stall))
+		return 1;
+
+	if(skb_fifo_len >= (E1000_82547_PAD_LEN + fifo_space)) {
+		atomic_set(&adapter->tx_fifo_stall, 1);
+		return 1;
+	}
+
+no_fifo_stall_required:
+	adapter->tx_fifo_head += skb_fifo_len;
+	if(adapter->tx_fifo_head >= adapter->tx_fifo_size)
+		adapter->tx_fifo_head -= adapter->tx_fifo_size;
+	return 0;
+}
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> E1000_MAX_TXD_PWR) + \
+			 (((S) & (E1000_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#define DESC_NEEDED TXD_USE_COUNT(MAX_JUMBO_FRAME_SIZE) + \
+	MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1
 
 static int
 e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev->priv;
-	int tx_flags = 0, count;
-	int f;
+	int tx_flags = 0;
 
-	count = TXD_USE_COUNT(skb->len - skb->data_len,
-	                      adapter->max_data_per_txd);
-
-	if(count == 0) {
+	if(skb->len <= 0) {
 		dev_kfree_skb_any(skb);
 		return 0;
 	}
 
-	for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
-		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
-		                       adapter->max_data_per_txd);
-	if((skb_shinfo(skb)->tso_size) || (skb->ip_summed == CHECKSUM_HW))
-		count++;
-
-	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+	if(E1000_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED) {
 		netif_stop_queue(netdev);
 		return 1;
 	}
 
+	if(adapter->hw.mac_type == e1000_82547) {
+		if(e1000_82547_fifo_workaround(adapter, skb)) {
+			netif_stop_queue(netdev);
+			mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
+			return 1;
+		}
+	}
+
 	if(adapter->vlgrp && vlan_tx_tag_present(skb)) {
 		tx_flags |= E1000_TX_FLAGS_VLAN;
 		tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
@@ -1530,9 +1709,7 @@
 	else if(e1000_tx_csum(adapter, skb))
 		tx_flags |= E1000_TX_FLAGS_CSUM;
 
-	count = e1000_tx_map(adapter, skb);
-
-	e1000_tx_queue(adapter, count, tx_flags);
+	e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags);
 
 	netdev->trans_start = jiffies;
 
@@ -1653,7 +1830,8 @@
 
 	adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS);
 	adapter->stats.gprc += E1000_READ_REG(hw, GPRC);
-	adapter->stats.gorcl += E1000_READ_REG(hw, GORCL);
+	adapter->gorcl = E1000_READ_REG(hw, GORCL);
+	adapter->stats.gorcl += adapter->gorcl;
 	adapter->stats.gorch += E1000_READ_REG(hw, GORCH);
 	adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
 	adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
@@ -1684,7 +1862,8 @@
 	adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC);
 	adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC);
 	adapter->stats.gptc += E1000_READ_REG(hw, GPTC);
-	adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL);
+	adapter->gotcl = E1000_READ_REG(hw, GOTCL);
+	adapter->stats.gotcl += adapter->gotcl;
 	adapter->stats.gotch += E1000_READ_REG(hw, GOTCH);
 	adapter->stats.rnbc += E1000_READ_REG(hw, RNBC);
 	adapter->stats.ruc += E1000_READ_REG(hw, RUC);
@@ -1807,60 +1986,57 @@
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev->priv;
-	
-#ifdef CONFIG_E1000_NAPI
-	if (netif_rx_schedule_prep(netdev)) {
-		/* Disable interrupts and enable polling */
-		atomic_inc(&adapter->irq_sem);
-		E1000_WRITE_REG(&adapter->hw, IMC, ~0);
-		E1000_WRITE_FLUSH(&adapter->hw);
-		__netif_rx_schedule(netdev);
-	}
-#else
-	uint32_t icr;
-	int i = E1000_MAX_INTR;
-
-	while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
-
-		if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
-			adapter->hw.get_link_status = 1;
-			mod_timer(&adapter->watchdog_timer, jiffies);
-		}
+	uint32_t icr = E1000_READ_REG(&adapter->hw, ICR);
+#ifndef CONFIG_E1000_NAPI
+	int i;
+#endif
 
-		e1000_clean_rx_irq(adapter);
-		e1000_clean_tx_irq(adapter);
-		i--;
+	if(!icr)
+		return;  /* Not our interrupt */
 
+	if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+		adapter->hw.get_link_status = 1;
+		mod_timer(&adapter->watchdog_timer, jiffies);
 	}
+
+#ifdef CONFIG_E1000_NAPI
+	/* Don't disable interrupts - rely on h/w interrupt
+	 * moderation to keep interrupts low.  netif_rx_schedule
+	 * is NOP if already polling. */
+	netif_rx_schedule(netdev);
+#else
+	for(i = 0; i < E1000_MAX_INTR; i++)
+		if(!e1000_clean_rx_irq(adapter) &&
+		   !e1000_clean_tx_irq(adapter))
+			break;
 #endif
 }
 
 #ifdef CONFIG_E1000_NAPI
+/**
+ * e1000_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+
 static int
-e1000_process_intr(struct net_device *netdev)
+e1000_clean(struct net_device *netdev, int *budget)
 {
 	struct e1000_adapter *adapter = netdev->priv;
-	uint32_t icr;
-	int i = E1000_MAX_INTR;
-	int hasReceived = 0;
-
-	while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
-		if (icr & E1000_ICR_RXT0)
-			hasReceived = 1;
- 
-		if (!(icr & ~(E1000_ICR_RXT0)))
+	int work_to_do = min(*budget, netdev->quota);
+	int work_done = 0;
+	
+	while(work_done < work_to_do)
+		if(!e1000_clean_rx_irq(adapter, &work_done, work_to_do) &&
+		   !e1000_clean_tx_irq(adapter))
 			break;
-    
-		if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
-			adapter->hw.get_link_status = 1;
-			mod_timer(&adapter->watchdog_timer, jiffies);
-		}
- 
-		e1000_clean_tx_irq(adapter);
-		i--;
-	}
 
-	return hasReceived;
+	*budget -= work_done;
+	netdev->quota -= work_done;
+	
+	if(work_done < work_to_do)
+		netif_rx_complete(netdev);
+
+	return (work_done >= work_to_do);
 }
 #endif
 
@@ -1869,20 +2045,22 @@
  * @adapter: board private structure
  **/
 
-static void
+static boolean_t
 e1000_clean_tx_irq(struct e1000_adapter *adapter)
 {
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
 	struct e1000_tx_desc *tx_desc;
-	int i;
+	int i, cleaned = FALSE;
 
 	i = tx_ring->next_to_clean;
 	tx_desc = E1000_TX_DESC(*tx_ring, i);
 
 	while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
 
+		cleaned = TRUE;
+
 		if(tx_ring->buffer_info[i].dma) {
 
 			pci_unmap_page(pdev,
@@ -1900,158 +2078,34 @@
 			tx_ring->buffer_info[i].skb = NULL;
 		}
 
+		tx_desc->buffer_addr = 0;
+		tx_desc->lower.data = 0;
 		tx_desc->upper.data = 0;
 
-		i = (i + 1) % tx_ring->count;
+		if(++i == tx_ring->count) i = 0;
 		tx_desc = E1000_TX_DESC(*tx_ring, i);
 	}
 
 	tx_ring->next_to_clean = i;
 
-	if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
-	   (E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) {
-
+	if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))
 		netif_wake_queue(netdev);
-	}
-}
-
-#ifdef CONFIG_E1000_NAPI
-static int
-e1000_poll(struct net_device *netdev, int *budget)
-{
-	struct e1000_adapter *adapter = netdev->priv;
-	struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
-	struct pci_dev *pdev = adapter->pdev;
-	struct e1000_rx_desc *rx_desc;
-	struct sk_buff *skb;
-	unsigned long flags;
-	uint32_t length;
-	uint8_t last_byte;
-	int i;
-	int received = 0;
-	int rx_work_limit = *budget;
-
-	if(rx_work_limit > netdev->quota)
-		rx_work_limit = netdev->quota;
-
-	e1000_process_intr(netdev);
-
-	i = rx_ring->next_to_clean;
-	rx_desc = E1000_RX_DESC(*rx_ring, i);
-
-	while(rx_desc->status & E1000_RXD_STAT_DD) {
-		if(--rx_work_limit < 0)
-			goto not_done;
-
-		pci_unmap_single(pdev,
-		                 rx_ring->buffer_info[i].dma,
-		                 rx_ring->buffer_info[i].length,
-		                 PCI_DMA_FROMDEVICE);
-
-		skb = rx_ring->buffer_info[i].skb;
-		length = le16_to_cpu(rx_desc->length);
-
-		if(!(rx_desc->status & E1000_RXD_STAT_EOP)) {
-
-			/* All receives must fit into a single buffer */
-
-			E1000_DBG("Receive packet consumed multiple buffers\n");
-
-			dev_kfree_skb_irq(skb);
-			rx_desc->status = 0;
-			rx_ring->buffer_info[i].skb = NULL;
-
-			i = (i + 1) % rx_ring->count;
-
-			rx_desc = E1000_RX_DESC(*rx_ring, i);
-			continue;
-		}
-
-		if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
-
-			last_byte = *(skb->data + length - 1);
-
-			if(TBI_ACCEPT(&adapter->hw, rx_desc->status,
-			              rx_desc->errors, length, last_byte)) {
-
-				spin_lock_irqsave(&adapter->stats_lock, flags);
-
-				e1000_tbi_adjust_stats(&adapter->hw,
-				                       &adapter->stats,
-				                       length, skb->data);
-
-				spin_unlock_irqrestore(&adapter->stats_lock,
-				                       flags);
-				length--;
-			} else {
-
-				dev_kfree_skb_irq(skb);
-				rx_desc->status = 0;
-				rx_ring->buffer_info[i].skb = NULL;
-
-				i = (i + 1) % rx_ring->count;
 
-				rx_desc = E1000_RX_DESC(*rx_ring, i);
-				continue;
-			}
-		}
-
-		/* Good Receive */
-		skb_put(skb, length - ETHERNET_FCS_SIZE);
-
-		/* Receive Checksum Offload */
-		e1000_rx_checksum(adapter, rx_desc, skb);
-
-		skb->protocol = eth_type_trans(skb, netdev);
-		if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
-			vlan_hwaccel_rx(skb, adapter->vlgrp,
-				(rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
-		} else {
-			netif_receive_skb(skb);
-		}
-		netdev->last_rx = jiffies;
-
-		rx_desc->status = 0;
-		rx_ring->buffer_info[i].skb = NULL;
-
-		i = (i + 1) % rx_ring->count;
-
-		rx_desc = E1000_RX_DESC(*rx_ring, i);
-		received++;
-	}
-
-	if(!received)
-		received = 1;
-
-	e1000_alloc_rx_buffers(adapter);
-	
-	rx_ring->next_to_clean = i;
-	netdev->quota -= received;
-	*budget -= received;
-
-	netif_rx_complete(netdev);
-
-	e1000_irq_enable(adapter);
-	return 0;
-
-not_done:
-
-	e1000_alloc_rx_buffers(adapter);
-	
-	rx_ring->next_to_clean = i;
-	netdev->quota -= received;
-	*budget -= received;
-
-	return 1;
+	return cleaned;
 }
-#else
+
 /**
  * e1000_clean_rx_irq - Send received data up the network stack,
  * @adapter: board private structure
  **/
 
-static void
+static boolean_t
+#ifdef CONFIG_E1000_NAPI
+e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done,
+                   int work_to_do)
+#else
 e1000_clean_rx_irq(struct e1000_adapter *adapter)
+#endif
 {
 	struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
 	struct net_device *netdev = adapter->netdev;
@@ -2061,13 +2115,22 @@
 	unsigned long flags;
 	uint32_t length;
 	uint8_t last_byte;
-	int i;
+	int i, cleaned = FALSE;
 
 	i = rx_ring->next_to_clean;
 	rx_desc = E1000_RX_DESC(*rx_ring, i);
 
 	while(rx_desc->status & E1000_RXD_STAT_DD) {
 
+#ifdef CONFIG_E1000_NAPI
+		if(*work_done >= work_to_do)
+			break;
+
+		(*work_done)++;
+#endif
+
+		cleaned = TRUE;
+
 		pci_unmap_single(pdev,
 		                 rx_ring->buffer_info[i].dma,
 		                 rx_ring->buffer_info[i].length,
@@ -2086,7 +2149,7 @@
 			rx_desc->status = 0;
 			rx_ring->buffer_info[i].skb = NULL;
 
-			i = (i + 1) % rx_ring->count;
+			if(++i == rx_ring->count) i = 0;
 
 			rx_desc = E1000_RX_DESC(*rx_ring, i);
 			continue;
@@ -2114,7 +2177,7 @@
 				rx_desc->status = 0;
 				rx_ring->buffer_info[i].skb = NULL;
 
-				i = (i + 1) % rx_ring->count;
+				if(++i == rx_ring->count) i = 0;
 
 				rx_desc = E1000_RX_DESC(*rx_ring, i);
 				continue;
@@ -2128,18 +2191,28 @@
 		e1000_rx_checksum(adapter, rx_desc, skb);
 
 		skb->protocol = eth_type_trans(skb, netdev);
+#ifdef CONFIG_E1000_NAPI
+		if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+			vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+				(rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
+		} else {
+			netif_receive_skb(skb);
+		}
+#else /* CONFIG_E1000_NAPI */
 		if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
 			vlan_hwaccel_rx(skb, adapter->vlgrp,
 				(rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
 		} else {
 			netif_rx(skb);
 		}
+#endif /* CONFIG_E1000_NAPI */
+
 		netdev->last_rx = jiffies;
 
 		rx_desc->status = 0;
 		rx_ring->buffer_info[i].skb = NULL;
 
-		i = (i + 1) % rx_ring->count;
+		if(++i == rx_ring->count) i = 0;
 
 		rx_desc = E1000_RX_DESC(*rx_ring, i);
 	}
@@ -2147,8 +2220,9 @@
 	rx_ring->next_to_clean = i;
 
 	e1000_alloc_rx_buffers(adapter);
+
+	return cleaned;
 }
-#endif
 
 /**
  * e1000_alloc_rx_buffers - Replace used receive buffers
@@ -2163,11 +2237,9 @@
 	struct pci_dev *pdev = adapter->pdev;
 	struct e1000_rx_desc *rx_desc;
 	struct sk_buff *skb;
-	int reserve_len;
+	int reserve_len = 2;
 	int i;
 
-	reserve_len = 2;
-
 	i = rx_ring->next_to_use;
 
 	while(!rx_ring->buffer_info[i].skb) {
@@ -2198,7 +2270,7 @@
 
 		rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
 
-		if(!(i % E1000_RX_BUFFER_WRITE)) {
+		if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) {
 			/* Force memory writes to complete before letting h/w
 			 * know there are new descriptors to fetch.  (Only
 			 * applicable for weak-ordered memory model archs,
@@ -2208,13 +2280,68 @@
 			E1000_WRITE_REG(&adapter->hw, RDT, i);
 		}
 
-		i = (i + 1) % rx_ring->count;
+		if(++i == rx_ring->count) i = 0;
 	}
 
 	rx_ring->next_to_use = i;
 }
 
 /**
+ * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers.
+ * @adapter:
+ **/
+
+static void
+e1000_smartspeed(struct e1000_adapter *adapter)
+{
+	uint16_t phy_status;
+	uint16_t phy_ctrl;
+
+	if((adapter->hw.phy_type != e1000_phy_igp) || !adapter->hw.autoneg ||
+	   !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL))
+		return;
+
+	if(adapter->smartspeed == 0) {
+		/* If Master/Slave config fault is asserted twice,
+		 * we assume back-to-back */
+		e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status);
+		if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
+		e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status);
+		if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
+		e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl);
+		if(phy_ctrl & CR_1000T_MS_ENABLE) {
+			phy_ctrl &= ~CR_1000T_MS_ENABLE;
+			e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL,
+					    phy_ctrl);
+			adapter->smartspeed++;
+			if(!e1000_phy_setup_autoneg(&adapter->hw) &&
+			   !e1000_read_phy_reg(&adapter->hw, PHY_CTRL,
+				   	       &phy_ctrl)) {
+				phy_ctrl |= (MII_CR_AUTO_NEG_EN |
+					     MII_CR_RESTART_AUTO_NEG);
+				e1000_write_phy_reg(&adapter->hw, PHY_CTRL,
+						    phy_ctrl);
+			}
+		}
+		return;
+	} else if(adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) {
+		/* If still no link, perhaps using 2/3 pair cable */
+		e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl);
+		phy_ctrl |= CR_1000T_MS_ENABLE;
+		e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl);
+		if(!e1000_phy_setup_autoneg(&adapter->hw) &&
+		   !e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) {
+			phy_ctrl |= (MII_CR_AUTO_NEG_EN |
+				     MII_CR_RESTART_AUTO_NEG);
+			e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_ctrl);
+		}
+	}
+	/* Restart process after E1000_SMARTSPEED_MAX iterations */
+	if(adapter->smartspeed++ == E1000_SMARTSPEED_MAX)
+		adapter->smartspeed = 0;
+}
+
+/**
  * e1000_ioctl -
  * @netdev:
  * @ifreq:
@@ -2225,6 +2352,10 @@
 e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
 	switch (cmd) {
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		return e1000_mii_ioctl(netdev, ifr, cmd);
 	case SIOCETHTOOL:
 		return e1000_ethtool_ioctl(netdev, ifr);
 	default:
@@ -2233,6 +2364,86 @@
 }
 
 /**
+ * e1000_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+
+static int
+e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	int retval;
+	uint16_t mii_reg;
+	uint16_t spddplx;
+
+	if(adapter->hw.media_type == e1000_media_type_fiber)
+		return -EOPNOTSUPP;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = adapter->hw.phy_addr;
+		break;
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+				   &data->val_out))
+			return -EIO;
+		break;
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (data->reg_num & ~(0x1F))
+			return -EFAULT;
+		mii_reg = data->val_in;
+		if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
+					data->val_in))
+			return -EIO;
+		if (adapter->hw.phy_type == e1000_phy_m88) {
+			switch (data->reg_num) {
+			case PHY_CTRL:
+				if(data->val_in & MII_CR_AUTO_NEG_EN) {
+					adapter->hw.autoneg = 1;
+					adapter->hw.autoneg_advertised = 0x2F;
+				} else {
+					if (data->val_in & 0x40)
+						spddplx = SPEED_1000;
+					else if (data->val_in & 0x2000)
+						spddplx = SPEED_100;
+					else
+						spddplx = SPEED_10;
+					spddplx += (data->val_in & 0x100)
+						   ? FULL_DUPLEX :
+						   HALF_DUPLEX;
+					retval = e1000_set_spd_dplx(adapter,
+								    spddplx);
+					if(retval)
+						return retval;
+				}
+				if(netif_running(adapter->netdev)) {
+					e1000_down(adapter);
+					e1000_up(adapter);
+				} else
+					e1000_reset(adapter);
+				break;
+			case M88E1000_PHY_SPEC_CTRL:
+			case M88E1000_EXT_PHY_SPEC_CTRL:
+				if (e1000_phy_reset(&adapter->hw))
+					return -EIO;
+				break;
+			}
+		}
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return E1000_SUCCESS;
+}
+
+/**
  * e1000_rx_checksum - Receive Checksum Offload for 82543
  * @adapter: board private structure
  * @rx_desc: receive descriptor
@@ -2402,6 +2613,35 @@
 	}
 }
 
+int
+e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx)
+{
+	adapter->hw.autoneg = 0;
+
+	switch(spddplx) {
+	case SPEED_10 + DUPLEX_HALF:
+		adapter->hw.forced_speed_duplex = e1000_10_half;
+		break;
+	case SPEED_10 + DUPLEX_FULL:
+		adapter->hw.forced_speed_duplex = e1000_10_full;
+		break;
+	case SPEED_100 + DUPLEX_HALF:
+		adapter->hw.forced_speed_duplex = e1000_100_half;
+		break;
+	case SPEED_100 + DUPLEX_FULL:
+		adapter->hw.forced_speed_duplex = e1000_100_full;
+		break;
+	case SPEED_1000 + DUPLEX_FULL:
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+		break;
+	case SPEED_1000 + DUPLEX_HALF: /* not supported */
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int
 e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
 {
@@ -2419,6 +2659,7 @@
 	return NOTIFY_DONE;
 }
 
+
 static int
 e1000_suspend(struct pci_dev *pdev, uint32_t state)
 {
@@ -2483,7 +2724,8 @@
 		if(manc & E1000_MANC_SMBUS_EN) {
 			manc |= E1000_MANC_ARP_EN;
 			E1000_WRITE_REG(&adapter->hw, MANC, manc);
-			state = 0;
+			pci_enable_wake(pdev, 3, 1);
+			pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */
 		}
 	}
 
diff -urN linux-2.5.65-bk1/drivers/net/e1000/e1000_osdep.h linux-2.5.65-bk2/drivers/net/e1000/e1000_osdep.h
--- linux-2.5.65-bk1/drivers/net/e1000/e1000_osdep.h	Mon Mar 17 13:43:48 2003
+++ linux-2.5.65-bk2/drivers/net/e1000/e1000_osdep.h	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -77,24 +77,22 @@
 
 
 #define E1000_WRITE_REG(a, reg, value) ( \
-    ((a)->mac_type >= e1000_82543) ? \
-        (writel((value), ((a)->hw_addr + E1000_##reg))) : \
-        (writel((value), ((a)->hw_addr + E1000_82542_##reg))))
+    writel((value), ((a)->hw_addr + \
+        (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))))
 
 #define E1000_READ_REG(a, reg) ( \
-    ((a)->mac_type >= e1000_82543) ? \
-        readl((a)->hw_addr + E1000_##reg) : \
-        readl((a)->hw_addr + E1000_82542_##reg))
+    readl((a)->hw_addr + \
+        (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))
 
 #define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
-    ((a)->mac_type >= e1000_82543) ? \
-        writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \
-        writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))))
+    writel((value), ((a)->hw_addr + \
+        (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+        ((offset) << 2))))
 
 #define E1000_READ_REG_ARRAY(a, reg, offset) ( \
-    ((a)->mac_type >= e1000_82543) ? \
-        readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \
-        readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))
+    readl((a)->hw_addr + \
+        (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+        ((offset) << 2)))
 
 #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
 
diff -urN linux-2.5.65-bk1/drivers/net/e1000/e1000_param.c linux-2.5.65-bk2/drivers/net/e1000/e1000_param.c
--- linux-2.5.65-bk1/drivers/net/e1000/e1000_param.c	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/drivers/net/e1000/e1000_param.c	Mon Mar 31 12:39:50 2003
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -169,7 +169,7 @@
  *
  * Valid Range: 0-65535
  *
- * Default Value: 0/128
+ * Default Value: 0
  */
 
 E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
@@ -183,6 +183,15 @@
 
 E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
 
+/* Interrupt Throttle Rate (interrupts/sec)
+ *
+ * Valid Range: 100-100000 (0=off, 1=dynamic)
+ *
+ * Default Value: 1
+ */
+
+E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
+
 #define AUTONEG_ADV_DEFAULT  0x2F
 #define AUTONEG_ADV_MASK     0x2F
 #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
@@ -213,6 +222,10 @@
 #define MAX_TXABSDELAY            0xFFFF
 #define MIN_TXABSDELAY                 0
 
+#define DEFAULT_ITR                    1
+#define MAX_ITR                   100000
+#define MIN_ITR                      100
+
 struct e1000_option {
 	enum { enable_option, range_option, list_option } type;
 	char *name;
@@ -309,7 +322,7 @@
 			.name = "Transmit Descriptors",
 			.err  = "using default of " __MODULE_STRING(DEFAULT_TXD),
 			.def  = DEFAULT_TXD,
-			.arg  = { .r = { .min = MIN_TXD }}
+			.arg  = { .r { .min = MIN_TXD }}
 		};
 		struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 		e1000_mac_type mac_type = adapter->hw.mac_type;
@@ -362,7 +375,8 @@
 			.name = "Flow Control",
 			.err  = "reading default settings from EEPROM",
 			.def  = e1000_fc_default,
-			.arg  = { .l = { .nr = ARRAY_SIZE(fc_list), .p = fc_list }}
+			.arg  = { .l = { .nr = ARRAY_SIZE(fc_list),
+					 .p = fc_list }}
 		};
 
 		int fc = FlowControl[bd];
@@ -370,58 +384,78 @@
 		adapter->hw.fc = adapter->hw.original_fc = fc;
 	}
 	{ /* Transmit Interrupt Delay */
-		char *tidv = "using default of " __MODULE_STRING(DEFAULT_TIDV);
 		struct e1000_option opt = {
 			.type = range_option,
 			.name = "Transmit Interrupt Delay",
-			.arg  = { .r = { .min = MIN_TXDELAY, .max = MAX_TXDELAY }}
+			.err  = "using default of " __MODULE_STRING(DEFAULT_TIDV),
+			.def  = DEFAULT_TIDV,
+			.arg  = { .r = { .min = MIN_TXDELAY,
+					 .max = MAX_TXDELAY }}
 		};
-		opt.def = DEFAULT_TIDV;
-		opt.err = tidv;
 
 		adapter->tx_int_delay = TxIntDelay[bd];
 		e1000_validate_option(&adapter->tx_int_delay, &opt);
 	}
 	{ /* Transmit Absolute Interrupt Delay */
-		char *tadv = "using default of " __MODULE_STRING(DEFAULT_TADV);
 		struct e1000_option opt = {
 			.type = range_option,
 			.name = "Transmit Absolute Interrupt Delay",
-			.arg  = { .r = { .min = MIN_TXABSDELAY, .max = MAX_TXABSDELAY }}
+			.err  = "using default of " __MODULE_STRING(DEFAULT_TADV),
+			.def  = DEFAULT_TADV,
+			.arg  = { .r = { .min = MIN_TXABSDELAY,
+					 .max = MAX_TXABSDELAY }}
 		};
-		opt.def = DEFAULT_TADV;
-		opt.err = tadv;
 
 		adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
 		e1000_validate_option(&adapter->tx_abs_int_delay, &opt);
 	}
 	{ /* Receive Interrupt Delay */
-		char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
 		struct e1000_option opt = {
 			.type = range_option,
 			.name = "Receive Interrupt Delay",
-			.arg  = { .r = { .min = MIN_RXDELAY, .max = MAX_RXDELAY }}
+			.err  = "using default of " __MODULE_STRING(DEFAULT_RDTR),
+			.def  = DEFAULT_RDTR,
+			.arg  = { .r = { .min = MIN_RXDELAY,
+					 .max = MAX_RXDELAY }}
 		};
-		opt.def = DEFAULT_RDTR;
-		opt.err = rdtr;
 
 		adapter->rx_int_delay = RxIntDelay[bd];
 		e1000_validate_option(&adapter->rx_int_delay, &opt);
 	}
 	{ /* Receive Absolute Interrupt Delay */
-		char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
 		struct e1000_option opt = {
 			.type = range_option,
 			.name = "Receive Absolute Interrupt Delay",
-			.arg  = { .r = { .min = MIN_RXABSDELAY, .max = MAX_RXABSDELAY }}
+			.err  = "using default of " __MODULE_STRING(DEFAULT_RADV),
+			.def  = DEFAULT_RADV,
+			.arg  = { .r = { .min = MIN_RXABSDELAY,
+					 .max = MAX_RXABSDELAY }}
 		};
-		opt.def = DEFAULT_RADV;
-		opt.err = radv;
 
 		adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
 		e1000_validate_option(&adapter->rx_abs_int_delay, &opt);
 	}
-	
+	{ /* Interrupt Throttling Rate */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Interrupt Throttling Rate (ints/sec)",
+			.err  = "using default of " __MODULE_STRING(DEFAULT_ITR),
+			.def  = DEFAULT_ITR,
+			.arg  = { .r = { .min = MIN_ITR,
+					 .max = MAX_ITR }}
+		};
+
+		adapter->itr = InterruptThrottleRate[bd];
+		if(adapter->itr == 0) {
+			printk(KERN_INFO "%s turned off\n", opt.name);
+		} else if(adapter->itr == 1 || adapter->itr == -1) {
+			/* Dynamic mode */
+			adapter->itr = 1;
+		} else {
+			e1000_validate_option(&adapter->itr, &opt);
+		}
+	}
+
 	switch(adapter->hw.media_type) {
 	case e1000_media_type_fiber:
 		e1000_check_fiber_options(adapter);
@@ -486,7 +520,8 @@
 			.name = "Speed",
 			.err  = "parameter ignored",
 			.def  = 0,
-			.arg  = { .l = { .nr = ARRAY_SIZE(speed_list), .p = speed_list }}
+			.arg  = { .l = { .nr = ARRAY_SIZE(speed_list),
+					 .p = speed_list }}
 		};
 
 		speed = Speed[bd];
@@ -502,7 +537,8 @@
 			.name = "Duplex",
 			.err  = "parameter ignored",
 			.def  = 0,
-			.arg  = { .l = { .nr = ARRAY_SIZE(dplx_list), .p = dplx_list }}
+			.arg  = { .l = { .nr = ARRAY_SIZE(dplx_list),
+					 .p = dplx_list }}
 		};
 
 		dplx = Duplex[bd];
@@ -554,7 +590,8 @@
 			.name = "AutoNeg",
 			.err  = "parameter ignored",
 			.def  = AUTONEG_ADV_DEFAULT,
-			.arg  = { .l = { .nr = ARRAY_SIZE(an_list), .p = an_list }}
+			.arg  = { .l = { .nr = ARRAY_SIZE(an_list),
+					 .p = an_list }}
 		};
 
 		int an = AutoNeg[bd];
diff -urN linux-2.5.65-bk1/drivers/net/macmace.c linux-2.5.65-bk2/drivers/net/macmace.c
--- linux-2.5.65-bk1/drivers/net/macmace.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/drivers/net/macmace.c	Mon Mar 31 12:39:50 2003
@@ -331,8 +331,8 @@
 		return -ENOMEM;
 	}
 
-	mp->rx_ring_phys = (unsigned char *) virt_to_bus(mp->rx_ring);
-	mp->tx_ring_phys = (unsigned char *) virt_to_bus(mp->tx_ring);
+	mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring);
+	mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring);
 
 	/* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */
 
diff -urN linux-2.5.65-bk1/drivers/net/ne2k_cbus.c linux-2.5.65-bk2/drivers/net/ne2k_cbus.c
--- linux-2.5.65-bk1/drivers/net/ne2k_cbus.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/drivers/net/ne2k_cbus.c	Mon Mar 31 12:39:50 2003
@@ -0,0 +1,879 @@
+/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
+/*
+    Written 1992-94 by Donald Becker.
+
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.
+
+    This software may be used and distributed according to the terms
+    of the GNU General Public License, incorporated herein by reference.
+
+    The author may be reached as becker@scyld.com, or C/O
+    Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+    This driver should work with many programmed-I/O 8390-based ethernet
+    boards.  Currently it supports the NE1000, NE2000, many clones,
+    and some Cabletron products.
+
+    Changelog:
+
+    Paul Gortmaker	: use ENISR_RDC to monitor Tx PIO uploads, made
+			  sanity checks and bad clone support optional.
+    Paul Gortmaker	: new reset code, reset card after probe at boot.
+    Paul Gortmaker	: multiple card support for module users.
+    Paul Gortmaker	: Support for PCI ne2k clones, similar to lance.c
+    Paul Gortmaker	: Allow users with bad cards to avoid full probe.
+    Paul Gortmaker	: PCI probe changes, more PCI cards supported.
+    rjohnson@analogic.com : Changed init order so an interrupt will only
+    occur after memory is allocated for dev->priv. Deallocated memory
+    last in cleanup_modue()
+    Richard Guenther    : Added support for ISAPnP cards
+    Paul Gortmaker	: Discontinued PCI support - use ne2k-pci.c instead.
+    Osamu Tomita	: Separate driver for NEC PC-9800.
+
+*/
+
+/* Routines for the NatSemi-based designs (NE[12]000). */
+
+static const char version1[] =
+"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n";
+static const char version2[] =
+"Last modified Nov 1, 2000 by Paul Gortmaker\n";
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/isapnp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "8390.h"
+
+/* Some defines that people can play with if so inclined. */
+
+/* Do we support clones that don't adhere to 14,15 of the SAprom ? */
+#define SUPPORT_NE_BAD_CLONES
+
+/* Do we perform extra sanity checks on stuff ? */
+/* #define NE_SANITY_CHECK */
+
+/* Do we implement the read before write bugfix ? */
+/* #define NE_RW_BUGFIX */
+
+/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
+/* #define PACKETBUF_MEMSIZE	0x40 */
+
+#ifdef SUPPORT_NE_BAD_CLONES
+/* A list of bad clones that we none-the-less recognize. */
+static struct { const char *name8, *name16; unsigned char SAprefix[4];}
+bad_clone_list[] __initdata = {
+    {"LA/T-98?", "LA/T-98", {0x00, 0xa0, 0xb0}},	/* I/O Data */
+    {"EGY-98?", "EGY-98", {0x00, 0x40, 0x26}},		/* Melco EGY98 */
+    {"ICM?", "ICM-27xx-ET", {0x00, 0x80, 0xc8}},	/* ICM IF-27xx-ET */
+    {"CNET-98/EL?", "CNET(98)E/L", {0x00, 0x80, 0x4C}},	/* Contec CNET-98/EL */
+    {0,}
+};
+#endif
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE	 (dev->base_addr)
+#define NE_CMD	 	EI_SHIFT(0x00)
+#define NE_DATAPORT	EI_SHIFT(0x10)	/* NatSemi-defined port window offset. */
+#define NE_RESET	EI_SHIFT(0x1f) /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT	0x20
+
+#define NE1SM_START_PG	0x20	/* First page of TX buffer */
+#define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
+#define NESM_START_PG	0x40	/* First page of TX buffer */
+#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+#include "ne2k_cbus.h"
+
+int ne_probe(struct net_device *dev);
+static int ne_probe1(struct net_device *dev, int ioaddr);
+static int ne_open(struct net_device *dev);
+static int ne_close(struct net_device *dev);
+
+static void ne_reset_8390(struct net_device *dev);
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+			  int ring_page);
+static void ne_block_input(struct net_device *dev, int count,
+			  struct sk_buff *skb, int ring_offset);
+static void ne_block_output(struct net_device *dev, const int count,
+		const unsigned char *buf, const int start_page);
+
+
+/*  Probe for various non-shared-memory ethercards.
+
+   NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
+   buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
+   the SAPROM, while other supposed NE2000 clones must be detected by their
+   SA prefix.
+
+   Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+   mode results in doubled values, which can be detected and compensated for.
+
+   The probe is also responsible for initializing the card and filling
+   in the 'dev' and 'ei_status' structures.
+
+   We use the minimum memory size for some ethercard product lines, iff we can't
+   distinguish models.  You can increase the packet buffer size by setting
+   PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
+	E1010   starts at 0x100 and ends at 0x2000.
+	E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
+	E2010	 starts at 0x100 and ends at 0x4000.
+	E2010-x starts at 0x100 and ends at 0xffff.  */
+
+int __init ne_probe(struct net_device *dev)
+{
+	unsigned int base_addr = dev->base_addr;
+
+	SET_MODULE_OWNER(dev);
+
+	if (ei_debug > 2)
+		printk(KERN_DEBUG "ne_probe(): entered.\n");
+
+	/* If CONFIG_NET_CBUS,
+	   we need dev->priv->reg_offset BEFORE to probe */
+	if (ne2k_cbus_init(dev) != 0)
+		return -ENOMEM;
+
+	/* First check any supplied i/o locations. User knows best. <cough> */
+	if (base_addr > 0) {
+		int result;
+		const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+
+		if (ei_debug > 2)
+			printk(KERN_DEBUG "ne_probe(): call ne_probe_cbus(base_addr=0x%x)\n", base_addr);
+
+		result = ne_probe_cbus(dev, hw, base_addr);
+		if (result != 0)
+			ne2k_cbus_destroy(dev);
+
+		return result;
+	}
+
+	if (ei_debug > 2)
+		printk(KERN_DEBUG "ne_probe(): base_addr is not specified.\n");
+
+#ifndef MODULE
+	/* Last resort. The semi-risky C-Bus auto-probe. */
+	if (ei_debug > 2)
+		printk(KERN_DEBUG "ne_probe(): auto-probe start.\n");
+
+	{
+		const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+
+		if (hw && hw->hwtype) {
+			const unsigned short *plist;
+			for (plist = hw->portlist; *plist; plist++)
+				if (ne_probe_cbus(dev, hw, *plist) == 0)
+					return 0;
+		} else {
+			for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+				const unsigned short *plist;
+				for (plist = hw->portlist; *plist; plist++)
+					if (ne_probe_cbus(dev, hw, *plist) == 0)
+						return 0;
+			}
+		}
+	}
+#endif
+
+	ne2k_cbus_destroy(dev);
+
+	return -ENODEV;
+}
+
+static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr)
+{
+	if (ei_debug > 2)
+		printk(KERN_DEBUG "ne_probe_cbus(): entered. (called from %p)\n",
+		       __builtin_return_address(0));
+
+	if (hw && hw->hwtype) {
+		ne2k_cbus_set_hwtype(dev, hw, ioaddr);
+		return ne_probe1(dev, ioaddr);
+	} else {
+		/* auto detect */
+
+		printk(KERN_DEBUG "ne_probe_cbus(): try to determine hardware types.\n");
+		for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+			ne2k_cbus_set_hwtype(dev, hw, ioaddr);
+			if (ne_probe1(dev, ioaddr) == 0)
+				return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+static int __init ne_probe1(struct net_device *dev, int ioaddr)
+{
+	int i;
+	unsigned char SA_prom[32];
+	int wordlength = 2;
+	const char *name = NULL;
+	int start_page, stop_page;
+	int neX000, bad_card;
+	int reg0, ret;
+	static unsigned version_printed;
+	const struct ne2k_cbus_region *rlist;
+	const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+	if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+		outb_p(0, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE);
+		/* udelay(5000);	*/
+		outb_p(1, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE);
+		/* udelay(5000);	*/
+		outb_p((ioaddr & 0xf000) >> 8 | 0x08 | 0x01, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE + 2);
+		/* udelay(5000); */
+	}
+#endif
+
+	for (rlist = hw->regionlist; rlist->range; rlist++)
+		if (!request_region(ioaddr + rlist->start,
+					rlist->range, dev->name)) {
+			ret = -EBUSY;
+			goto err_out;
+		}
+
+	reg0 = inb_p(ioaddr + EI_SHIFT(0));
+	if (reg0 == 0xFF) {
+		ret = -ENODEV;
+		goto err_out;
+	}
+
+	/* Do a preliminary verification that we have a 8390. */
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+	if (hw->hwtype != NE2K_CBUS_HARDWARE_TYPE_CNET98EL)
+#endif
+	{
+		int regd;
+		outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
+		regd = inb_p(ioaddr + EI_SHIFT(0x0d));
+		outb_p(0xff, ioaddr + EI_SHIFT(0x0d));
+		outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
+		inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
+		if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
+			outb_p(reg0, ioaddr);
+			outb_p(regd, ioaddr + EI_SHIFT(0x0d));	/* Restore the old values. */
+			ret = -ENODEV;
+			goto err_out;
+		}
+	}
+
+	if (ei_debug  &&  version_printed++ == 0)
+		printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
+
+	printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr);
+
+	/* A user with a poor card that fails to ack the reset, or that
+	   does not have a valid 0x57,0x57 signature can still use this
+	   without having to recompile. Specifying an i/o address along
+	   with an otherwise unused dev->mem_end value of "0xBAD" will
+	   cause the driver to skip these parts of the probe. */
+
+	bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad));
+
+	/* Reset card. Who knows what dain-bramaged state it was left in. */
+
+	{
+		unsigned long reset_start_time = jiffies;
+
+		/* derived from CNET98EL-patch for bad clones */
+		outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD);
+
+		/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+		outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+		while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
+		if (jiffies - reset_start_time > 2*HZ/100) {
+			if (bad_card) {
+				printk(" (warning: no reset ack)");
+				break;
+			} else {
+				printk(" not found (no reset ack).\n");
+				ret = -ENODEV;
+				goto err_out;
+			}
+		}
+
+		outb_p(0xff, ioaddr + EN0_ISR);		/* Ack all intr. */
+	}
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+	if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+		static const char pat[32] ="AbcdeFghijKlmnoPqrstUvwxyZ789012";
+		char buf[32];
+		int maxwait = 200;
+
+		if (ei_debug > 2)
+			printk(" [CNET98EL-specific initialize...");
+		outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD); /* 0x20|0x1 */
+		i = inb(ioaddr);
+		if ((i & ~0x2) != (0x20 | 0x01))
+			return -ENODEV;
+		if ((inb(ioaddr + 0x7) & 0x80) != 0x80)
+			return -ENODEV;
+		outb_p(E8390_RXOFF, ioaddr + EN0_RXCR); /* out(ioaddr+0xc, 0x20) */
+		/* outb_p(ENDCFG_WTS|ENDCFG_FT1|ENDCFG_LS, ioaddr+EN0_DCFG); */
+		outb_p(ENDCFG_WTS | 0x48, ioaddr + EN0_DCFG); /* 0x49 */
+		outb_p(CNET98EL_START_PG, ioaddr + EN0_STARTPG);
+		outb_p(CNET98EL_STOP_PG, ioaddr + EN0_STOPPG);
+		if (ei_debug > 2)
+			printk("memory check");
+		for (i = 0; i < 65536; i += 1024) {
+			if (ei_debug > 2)
+				printk(" %04x", i);
+			ne2k_cbus_writemem(dev, ioaddr, i, pat, 32);
+			while (((inb(ioaddr + EN0_ISR) & ENISR_RDC) != ENISR_RDC) && --maxwait)
+				;
+			ne2k_cbus_readmem(dev, ioaddr, i, buf, 32);
+			if (memcmp(pat, buf, 32)) {
+				if (ei_debug > 2)
+					printk(" failed.");
+				break;
+			}
+		}
+		if (i != 16384) {
+			if (ei_debug > 2)
+				printk("] ");
+			printk("memory failure at %x\n", i);
+			return -ENODEV;
+		}
+		if (ei_debug > 2)
+			printk(" good...");
+		if (!dev->irq) {
+			if (ei_debug > 2)
+				printk("] ");
+			printk("IRQ must be specified for C-NET(98)E/L. probe failed.\n");
+			return -ENODEV;
+		}
+		outb((dev->irq > 5) ? (dev->irq & 4):(dev->irq >> 1), ioaddr + (0x2 | 0x400));
+		outb(0x7e, ioaddr + (0x4 | 0x400));
+		ne2k_cbus_readmem(dev, ioaddr, 16384, SA_prom, 32);
+		outb(0xff, ioaddr + EN0_ISR);
+		if (ei_debug > 2)
+			printk("done]");
+	} else
+#endif /* CONFIG_NE2K_CBUS_CNET98EL */
+	/* Read the 16 bytes of station address PROM.
+	   We must first initialize registers, similar to NS8390_init(eifdev, 0).
+	   We can't reliably read the SAPROM address without this.
+	   (I learned the hard way!). */
+	{
+		struct {unsigned char value; unsigned short offset;} program_seq[] = 
+		{
+			{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+			/* NEC PC-9800: some board can only handle word-wide access? */
+			{0x48 | ENDCFG_WTS,	EN0_DCFG},	/* Set word-wide (0x48) access. */
+			{16384 / 256, EN0_STARTPG},
+			{32768 / 256, EN0_STOPPG},
+			{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
+			{0x00,	EN0_RCNTHI},
+			{0x00,	EN0_IMR},	/* Mask completion irq. */
+			{0xFF,	EN0_ISR},
+			{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+			{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
+			{32,	EN0_RCNTLO},
+			{0x00,	EN0_RCNTHI},
+			{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
+			{0x00,	EN0_RSARHI},
+			{E8390_RREAD+E8390_START, E8390_CMD},
+		};
+
+		for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+			outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
+		insw(ioaddr + NE_DATAPORT, SA_prom, 32 >> 1);
+
+	}
+
+	if (wordlength == 2)
+	{
+		for (i = 0; i < 16; i++)
+			SA_prom[i] = SA_prom[i+i];
+		start_page = NESM_START_PG;
+		stop_page = NESM_STOP_PG;
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+		if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+			start_page = CNET98EL_START_PG;
+			stop_page = CNET98EL_STOP_PG;
+		}
+#endif
+	} else {
+		start_page = NE1SM_START_PG;
+		stop_page = NE1SM_STOP_PG;
+	}
+
+	neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
+	if (neX000) {
+		name = "C-Bus-NE2K-compat";
+	}
+	else
+	{
+#ifdef SUPPORT_NE_BAD_CLONES
+		/* Ack!  Well, there might be a *bad* NE*000 clone there.
+		   Check for total bogus addresses. */
+		for (i = 0; bad_clone_list[i].name8; i++)
+		{
+			if (SA_prom[0] == bad_clone_list[i].SAprefix[0] &&
+				SA_prom[1] == bad_clone_list[i].SAprefix[1] &&
+				SA_prom[2] == bad_clone_list[i].SAprefix[2])
+			{
+				if (wordlength == 2)
+				{
+					name = bad_clone_list[i].name16;
+				} else {
+					name = bad_clone_list[i].name8;
+				}
+				break;
+			}
+		}
+		if (bad_clone_list[i].name8 == NULL)
+		{
+			printk(" not found (invalid signature %2.2x %2.2x).\n",
+				SA_prom[14], SA_prom[15]);
+			ret = -ENXIO;
+			goto err_out;
+		}
+#else
+		printk(" not found.\n");
+		ret = -ENXIO;
+		goto err_out;
+#endif
+	}
+
+	if (dev->irq < 2)
+	{
+		unsigned long cookie = probe_irq_on();
+		outb_p(0x50, ioaddr + EN0_IMR);	/* Enable one interrupt. */
+		outb_p(0x00, ioaddr + EN0_RCNTLO);
+		outb_p(0x00, ioaddr + EN0_RCNTHI);
+		outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
+		mdelay(10);		/* wait 10ms for interrupt to propagate */
+		outb_p(0x00, ioaddr + EN0_IMR); 		/* Mask it again. */
+		dev->irq = probe_irq_off(cookie);
+		if (ei_debug > 2)
+			printk(" autoirq is %d\n", dev->irq);
+	} else if (dev->irq == 7)
+		/* Fixup for users that don't know that IRQ 7 is really IRQ 11,
+		   or don't know which one to set. */
+		dev->irq = 11;
+
+	if (! dev->irq) {
+		printk(" failed to detect IRQ line.\n");
+		ret = -EAGAIN;
+		goto err_out;
+	}
+
+	/* Allocate dev->priv and fill in 8390 specific dev fields. */
+	if (ethdev_init(dev))
+	{
+        	printk (" unable to get memory for dev->priv.\n");
+        	ret = -ENOMEM;
+		goto err_out;
+	}
+
+	/* Snarf the interrupt now.  There's no point in waiting since we cannot
+	   share and the board will usually be enabled. */
+	ret = request_irq(dev->irq, ei_interrupt, 0, name, dev);
+	if (ret) {
+		printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
+		goto err_out_kfree;
+	}
+
+	dev->base_addr = ioaddr;
+
+	for(i = 0; i < ETHER_ADDR_LEN; i++) {
+		printk(" %2.2x", SA_prom[i]);
+		dev->dev_addr[i] = SA_prom[i];
+	}
+
+	printk("\n%s: %s found at %#x, hardware type %d(%s), using IRQ %d.\n",
+		   dev->name, name, ioaddr, hw->hwtype, hw->hwident, dev->irq);
+
+	ei_status.name = name;
+	ei_status.tx_start_page = start_page;
+	ei_status.stop_page = stop_page;
+	ei_status.word16 = (wordlength == 2);
+
+	ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+	 /* Allow the packet buffer size to be overridden by know-it-alls. */
+	ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+	ei_status.reset_8390 = &ne_reset_8390;
+	ei_status.block_input = &ne_block_input;
+	ei_status.block_output = &ne_block_output;
+	ei_status.get_8390_hdr = &ne_get_8390_hdr;
+	ei_status.priv = 0;
+	dev->open = &ne_open;
+	dev->stop = &ne_close;
+	NS8390_init(dev, 0);
+	return 0;
+
+err_out_kfree:
+	ne2k_cbus_destroy(dev);
+err_out:
+	while (rlist > hw->regionlist) {
+		rlist --;
+		release_region(ioaddr + rlist->start, rlist->range);
+	}
+	return ret;
+}
+
+static int ne_open(struct net_device *dev)
+{
+	ei_open(dev);
+	return 0;
+}
+
+static int ne_close(struct net_device *dev)
+{
+	if (ei_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+	ei_close(dev);
+	return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+
+static void ne_reset_8390(struct net_device *dev)
+{
+	unsigned long reset_start_time = jiffies;
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+	if (ei_debug > 1)
+		printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
+
+	/* derived from CNET98EL-patch for bad clones... */
+	outb_p(E8390_NODMA | E8390_STOP, NE_BASE + E8390_CMD);  /* 0x20 | 0x1 */
+
+	/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+	outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+	ei_status.txing = 0;
+	ei_status.dmaing = 0;
+
+	/* This check _should_not_ be necessary, omit eventually. */
+	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+		if (jiffies - reset_start_time > 2*HZ/100) {
+			printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
+			break;
+		}
+	outb_p(ENISR_RESET, NE_BASE + EN0_ISR);	/* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	int nic_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+
+	if (ei_status.dmaing)
+	{
+		printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr "
+			"[DMAstat:%d][irqlock:%d].\n",
+			dev->name, ei_status.dmaing, ei_status.irqlock);
+		return;
+	}
+
+	ei_status.dmaing |= 0x01;
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+	outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+	outb_p(0, nic_base + EN0_RCNTHI);
+	outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
+	outb_p(ring_page, nic_base + EN0_RSARHI);
+	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+	if (ei_status.word16)
+		insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+	else
+		insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
+
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+
+	le16_to_cpus(&hdr->count);
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using outb. */
+
+static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+#ifdef NE_SANITY_CHECK
+	int xfer_count = count;
+#endif
+	int nic_base = dev->base_addr;
+	char *buf = skb->data;
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+	if (ei_status.dmaing)
+	{
+		printk(KERN_EMERG "%s: DMAing conflict in ne_block_input "
+			"[DMAstat:%d][irqlock:%d].\n",
+			dev->name, ei_status.dmaing, ei_status.irqlock);
+		return;
+	}
+	ei_status.dmaing |= 0x01;
+
+	/* round up count to a word (derived from ICM-patch) */
+	count = (count + 1) & ~1;
+
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+	outb_p(count >> 8, nic_base + EN0_RCNTHI);
+	outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
+	outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
+	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+	if (ei_status.word16)
+	{
+		insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+		if (count & 0x01)
+		{
+			buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+#ifdef NE_SANITY_CHECK
+			xfer_count++;
+#endif
+		}
+	} else {
+		insb(NE_BASE + NE_DATAPORT, buf, count);
+	}
+
+#ifdef NE_SANITY_CHECK
+	/* This was for the ALPHA version only, but enough people have
+	   been encountering problems so it is still here.  If you see
+	   this message you either 1) have a slightly incompatible clone
+	   or 2) have noise/speed problems with your bus. */
+
+	if (ei_debug > 1)
+	{
+		/* DMA termination address check... */
+		int addr, tries = 20;
+		do {
+			/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
+			   -- it's broken for Rx on some cards! */
+			int high = inb_p(nic_base + EN0_RSARHI);
+			int low = inb_p(nic_base + EN0_RSARLO);
+			addr = (high << 8) + low;
+			if (((ring_offset + xfer_count) & 0xff) == low)
+				break;
+		} while (--tries > 0);
+	 	if (tries <= 0)
+			printk(KERN_WARNING "%s: RX transfer address mismatch,"
+				"%#4.4x (expected) vs. %#4.4x (actual).\n",
+				dev->name, ring_offset + xfer_count, addr);
+	}
+#endif
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+}
+
+static void ne_block_output(struct net_device *dev, int count,
+		const unsigned char *buf, const int start_page)
+{
+	int nic_base = NE_BASE;
+	unsigned long dma_start;
+#ifdef NE_SANITY_CHECK
+	int retries = 0;
+#endif
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+
+	/* Round the count up for word writes.  Do we need to do this?
+	   What effect will an odd byte count have on the 8390?
+	   I should check someday. */
+
+	if (ei_status.word16 && (count & 0x01))
+		count++;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+	if (ei_status.dmaing)
+	{
+		printk(KERN_EMERG "%s: DMAing conflict in ne_block_output."
+			"[DMAstat:%d][irqlock:%d]\n",
+			dev->name, ei_status.dmaing, ei_status.irqlock);
+		return;
+	}
+	ei_status.dmaing |= 0x01;
+	/* We should already be in page 0, but to be safe... */
+	outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+#ifdef NE_SANITY_CHECK
+retry:
+#endif
+
+#ifdef NE8390_RW_BUGFIX
+	/* Handle the read-before-write bug the same way as the
+	   Crynwr packet driver -- the NatSemi method doesn't work.
+	   Actually this doesn't always work either, but if you have
+	   problems with your NEx000 this is better than nothing! */
+
+	outb_p(0x42, nic_base + EN0_RCNTLO);
+	outb_p(0x00,   nic_base + EN0_RCNTHI);
+	outb_p(0x42, nic_base + EN0_RSARLO);
+	outb_p(0x00, nic_base + EN0_RSARHI);
+	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+	/* Make certain that the dummy read has occurred. */
+	udelay(6);
+#endif
+
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);
+
+	/* Now the normal output. */
+	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+	outb_p(count >> 8,   nic_base + EN0_RCNTHI);
+	outb_p(0x00, nic_base + EN0_RSARLO);
+	outb_p(start_page, nic_base + EN0_RSARHI);
+
+	outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+	if (ei_status.word16) {
+		outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+	} else {
+		outsb(NE_BASE + NE_DATAPORT, buf, count);
+	}
+
+	dma_start = jiffies;
+
+#ifdef NE_SANITY_CHECK
+	/* This was for the ALPHA version only, but enough people have
+	   been encountering problems so it is still here. */
+
+	if (ei_debug > 1)
+	{
+		/* DMA termination address check... */
+		int addr, tries = 20;
+		do {
+			int high = inb_p(nic_base + EN0_RSARHI);
+			int low = inb_p(nic_base + EN0_RSARLO);
+			addr = (high << 8) + low;
+			if ((start_page << 8) + count == addr)
+				break;
+		} while (--tries > 0);
+
+		if (tries <= 0)
+		{
+			printk(KERN_WARNING "%s: Tx packet transfer address mismatch,"
+				"%#4.4x (expected) vs. %#4.4x (actual).\n",
+				dev->name, (start_page << 8) + count, addr);
+			if (retries++ == 0)
+				goto retry;
+		}
+	}
+#endif
+
+	while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+		if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+			printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
+			ne_reset_8390(dev);
+			NS8390_init(dev,1);
+			break;
+		}
+
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+	return;
+}
+
+
+#ifdef MODULE
+#define MAX_NE_CARDS	4	/* Max number of NE cards per module */
+static struct net_device dev_ne[MAX_NE_CARDS];
+static int io[MAX_NE_CARDS];
+static int irq[MAX_NE_CARDS];
+static int bad[MAX_NE_CARDS];	/* 0xbad = bad sig or no reset ack */
+static int hwtype[MAX_NE_CARDS] = { 0, }; /* board type */
+
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM(hwtype, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM_DESC(io, "I/O base address(es),required");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
+MODULE_PARM_DESC(hwtype, "Board type of PC-9800 C-Bus NIC");
+MODULE_DESCRIPTION("NE1000/NE2000 PC-9800 C-bus Ethernet driver");
+MODULE_LICENSE("GPL");
+
+/* This is set up so that no ISA autoprobe takes place. We can't guarantee
+that the ne2k probe is the last 8390 based probe to take place (as it
+is at boot) and so the probe will get confused by any other 8390 cards.
+ISA device autoprobes on a running machine are not recommended anyway. */
+
+int init_module(void)
+{
+	int this_dev, found = 0;
+
+	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+		struct net_device *dev = &dev_ne[this_dev];
+		dev->irq = irq[this_dev];
+		dev->mem_end = bad[this_dev];
+		dev->base_addr = io[this_dev];
+		dev->mem_start = hwtype[this_dev];
+		dev->init = ne_probe;
+		if (register_netdev(dev) == 0) {
+			found++;
+			continue;
+		}
+		if (found != 0) { 	/* Got at least one. */
+			return 0;
+		}
+		if (io[this_dev] != 0)
+			printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
+		else
+			printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for C-Bus cards.\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	int this_dev;
+
+	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+		struct net_device *dev = &dev_ne[this_dev];
+		if (dev->priv != NULL) {
+			const struct ne2k_cbus_region *rlist;
+			const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+
+			free_irq(dev->irq, dev);
+			for (rlist = hw->regionlist; rlist->range; rlist++) {
+				release_region(dev->base_addr + rlist->start,
+						rlist->range);
+			}
+			unregister_netdev(dev);
+			ne2k_cbus_destroy(dev);
+		}
+	}
+}
+#endif /* MODULE */
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ * End:
+ */
diff -urN linux-2.5.65-bk1/drivers/net/ne2k_cbus.h linux-2.5.65-bk2/drivers/net/ne2k_cbus.h
--- linux-2.5.65-bk1/drivers/net/ne2k_cbus.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/drivers/net/ne2k_cbus.h	Mon Mar 31 12:39:50 2003
@@ -0,0 +1,481 @@
+/* ne2k_cbus.h: 
+   vender-specific information definition for NEC PC-9800
+   C-bus Ethernet Cards
+   Used in ne.c 
+
+   (C)1998,1999 KITAGWA Takurou & Linux/98 project
+*/
+
+#include <linux/config.h>
+
+#undef NE_RESET
+#define NE_RESET EI_SHIFT(0x11) /* Issue a read to reset, a write to clear. */
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+#ifndef CONFIG_NE2K_CBUS_CNET98EL_IO_BASE
+#warning CONFIG_NE2K_CBUS_CNET98EL_IO_BASE is not defined(config error?)
+#warning use 0xaaed as default
+#define CONFIG_NE2K_CBUS_CNET98EL_IO_BASE 0xaaed /* or 0x55ed */
+#endif
+#define CNET98EL_START_PG 0x00
+#define CNET98EL_STOP_PG 0x40
+#endif
+
+/* Hardware type definition (derived from *BSD) */
+#define NE2K_CBUS_HARDWARE_TYPE_MASK 0xff
+
+/* 0: reserved for auto-detect */
+/* 1: (not tested)
+   Allied Telesis CentreCom LA-98-T */
+#define NE2K_CBUS_HARDWARE_TYPE_ATLA98 1
+/* 2: (not tested)
+   ELECOM Laneed
+   LD-BDN[123]A
+   PLANET SMART COM 98 EN-2298-C
+   MACNICA ME98 */
+#define NE2K_CBUS_HARDWARE_TYPE_BDN 2
+/* 3:
+   Melco EGY-98
+   Contec C-NET(98)E*A/L*A,C-NET(98)P */
+#define NE2K_CBUS_HARDWARE_TYPE_EGY98 3
+/* 4:
+   Melco LGY-98,IND-SP,IND-SS
+   MACNICA NE2098 */
+#define NE2K_CBUS_HARDWARE_TYPE_LGY98 4
+/* 5:
+   ICM DT-ET-25,DT-ET-T5,IF-2766ET,IF-2771ET
+   PLANET SMART COM 98 EN-2298-T,EN-2298P-T
+   D-Link DE-298PT,DE-298PCAT
+   ELECOM Laneed LD-98P */
+#define NE2K_CBUS_HARDWARE_TYPE_ICM 5
+/* 6: (reserved for SIC-98, which is not supported in this driver.) */
+/* 7: (unused in *BSD?)
+   <Original NE2000 compatible>
+   <for PCI/PCMCIA cards>
+*/
+#define NE2K_CBUS_HARDWARE_TYPE_NE2K 7
+/* 8:
+   NEC PC-9801-108 */
+#define NE2K_CBUS_HARDWARE_TYPE_NEC108 8
+/* 9:
+   I-O DATA LA-98,LA/T-98 */
+#define NE2K_CBUS_HARDWARE_TYPE_IOLA98 9
+/* 10: (reserved for C-NET(98), which is not supported in this driver.) */
+/* 11:
+   Contec C-NET(98)E,L */
+#define NE2K_CBUS_HARDWARE_TYPE_CNET98EL 11
+
+#define NE2K_CBUS_HARDWARE_TYPE_MAX 11
+
+/* HARDWARE TYPE ID 12-31: reserved */
+
+struct ne2k_cbus_offsetinfo {
+	unsigned short skip;
+	unsigned short offset8; /* +0x8 - +0xf */
+	unsigned short offset10; /* +0x10 */
+	unsigned short offset1f; /* +0x1f */
+};
+
+struct ne2k_cbus_region {
+	unsigned short start;
+	short range;
+};
+
+struct ne2k_cbus_hwinfo {
+	const unsigned short hwtype;
+	const unsigned char *hwident;
+#ifndef MODULE
+	const unsigned short *portlist;
+#endif
+	const struct ne2k_cbus_offsetinfo *offsetinfo;
+	const struct ne2k_cbus_region *regionlist;
+};
+
+#ifdef CONFIG_NE2K_CBUS_ATLA98
+#ifndef MODULE
+static unsigned short atla98_portlist[] __initdata = {
+	0xd0,
+	0
+};
+#endif
+#define atla98_offsetinfo ne2k_offsetinfo
+#define atla98_regionlist ne2k_regionlist
+#endif /* CONFIG_NE2K_CBUS_ATLA98 */
+
+#ifdef CONFIG_NE2K_CBUS_BDN
+#ifndef MODULE
+static unsigned short bdn_portlist[] __initdata = {
+	0xd0,
+	0
+};
+#endif
+static struct ne2k_cbus_offsetinfo bdn_offsetinfo __initdata = {
+#if 0
+	/* comes from FreeBSD(98) ed98.h */
+	0x1000, 0x8000, 0x100, 0xc200 /* ??? */
+#else
+	/* comes from NetBSD/pc98 if_ne_isa.c */
+	0x1000, 0x8000, 0x100, 0x7f00 /* ??? */
+#endif
+};
+static struct ne2k_cbus_region bdn_regionlist[] __initdata = {
+	{0x0, 1}, {0x1000, 1}, {0x2000, 1}, {0x3000,1},
+	{0x4000, 1}, {0x5000, 1}, {0x6000, 1}, {0x7000, 1},
+	{0x8000, 1}, {0x9000, 1}, {0xa000, 1}, {0xb000, 1},
+	{0xc000, 1}, {0xd000, 1}, {0xe000, 1}, {0xf000, 1},
+	{0x100, 1}, {0x7f00, 1},
+	{0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_BDN */
+
+#ifdef CONFIG_NE2K_CBUS_EGY98
+#ifndef MODULE
+static unsigned short egy98_portlist[] __initdata = {
+	0xd0,
+	0
+};
+#endif
+static struct ne2k_cbus_offsetinfo egy98_offsetinfo __initdata = {
+	0x02, 0x100, 0x200, 0x300
+};
+static struct ne2k_cbus_region egy98_regionlist[] __initdata = {
+	{0x0, 1}, {0x2, 1}, {0x4, 1}, {0x6, 1},
+	{0x8, 1}, {0xa, 1}, {0xc, 1}, {0xe, 1},
+	{0x100, 1}, {0x102, 1}, {0x104, 1}, {0x106, 1},
+	{0x108, 1}, {0x10a, 1}, {0x10c, 1}, {0x10e, 1},
+	{0x200, 1}, {0x300, 1},
+	{0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_EGY98 */
+
+#ifdef CONFIG_NE2K_CBUS_LGY98
+#ifndef MODULE
+static unsigned short lgy98_portlist[] __initdata = {
+	0xd0, 0x10d0, 0x20d0, 0x30d0, 0x40d0, 0x50d0, 0x60d0, 0x70d0,
+	0
+};
+#endif
+static struct ne2k_cbus_offsetinfo lgy98_offsetinfo __initdata = {
+	0x01, 0x08, 0x200, 0x300
+};
+static struct ne2k_cbus_region lgy98_regionlist[] __initdata = {
+	{0x0, 16}, {0x200, 1}, {0x300, 1},
+	{0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_LGY98 */
+
+#ifdef CONFIG_NE2K_CBUS_ICM
+#ifndef MODULE
+static unsigned short icm_portlist[] __initdata = {
+	/* ICM */
+	0x56d0,
+	/* LD-98PT */
+	0x46d0, 0x66d0, 0x76d0, 0x86d0, 0x96d0, 0xa6d0, 0xb6d0, 0xc6d0,
+	0
+};
+#endif
+static struct ne2k_cbus_offsetinfo icm_offsetinfo __initdata = {
+	0x01, 0x08, 0x100, 0x10f
+};
+static struct ne2k_cbus_region icm_regionlist[] __initdata = {
+	{0x0, 16}, {0x100, 16},
+	{0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_ICM */
+
+#if defined(CONFIG_NE2K_CBUS_NE2K) && !defined(MODULE)
+static unsigned short ne2k_portlist[] __initdata = {
+	0xd0, 0x300, 0x280, 0x320, 0x340, 0x360, 0x380,
+	0
+};
+#endif
+#if defined(CONFIG_NE2K_CBUS_NE2K) || defined(CONFIG_NE2K_CBUS_ATLA98)
+static struct ne2k_cbus_offsetinfo ne2k_offsetinfo __initdata = {
+	0x01, 0x08, 0x10, 0x1f
+};
+static struct ne2k_cbus_region ne2k_regionlist[] __initdata = {
+	{0x0, 32},
+	{0x0, 0}
+};
+#endif
+
+#ifdef CONFIG_NE2K_CBUS_NEC108
+#ifndef MODULE
+static unsigned short nec108_portlist[] __initdata = {
+	0x770, 0x2770, 0x4770, 0x6770,
+	0
+};
+#endif
+static struct ne2k_cbus_offsetinfo nec108_offsetinfo __initdata = {
+	0x02, 0x1000, 0x888, 0x88a
+};
+static struct ne2k_cbus_region nec108_regionlist[] __initdata = {
+	{0x0, 1}, {0x2, 1}, {0x4, 1}, {0x6, 1},
+	{0x8, 1}, {0xa, 1}, {0xc, 1}, {0xe, 1},
+	{0x1000, 1}, {0x1002, 1}, {0x1004, 1}, {0x1006, 1},
+	{0x1008, 1}, {0x100a, 1}, {0x100c, 1}, {0x100e, 1},
+	{0x888, 1}, {0x88a, 1}, {0x88c, 1}, {0x88e, 1},
+	{0x0, 0}
+};
+#endif
+
+#ifdef CONFIG_NE2K_CBUS_IOLA98
+#ifndef MODULE
+static unsigned short iola98_portlist[] __initdata = {
+	0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+	0
+};
+#endif
+static struct ne2k_cbus_offsetinfo iola98_offsetinfo __initdata = {
+	0x1000, 0x8000, 0x100, 0xf100
+};
+static struct ne2k_cbus_region iola98_regionlist[] __initdata = {
+	{0x0, 1}, {0x1000, 1}, {0x2000, 1}, {0x3000, 1},
+	{0x4000, 1}, {0x5000, 1}, {0x6000, 1}, {0x7000, 1},
+	{0x8000, 1}, {0x9000, 1}, {0xa000, 1}, {0xb000, 1},
+	{0xc000, 1}, {0xd000, 1}, {0xe000, 1}, {0xf000, 1},
+	{0x100, 1}, {0xf100, 1},
+	{0x0,0}
+};
+#endif /* CONFIG_NE2K_CBUS_IOLA98 */
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+#ifndef MODULE
+static unsigned short cnet98el_portlist[] __initdata = {
+	0x3d0, 0x13d0, 0x23d0, 0x33d0, 0x43d0, 0x53d0, 0x60d0, 0x70d0,
+	0
+};
+#endif
+static struct ne2k_cbus_offsetinfo cnet98el_offsetinfo __initdata = {
+	0x01, 0x08, 0x40e, 0x400
+};
+static struct ne2k_cbus_region cnet98el_regionlist[] __initdata = {
+	{0x0, 16}, {0x400, 16},
+	{0x0, 0}
+};
+#endif
+
+
+/* port information table (for ne.c initialize/probe process) */
+
+static struct ne2k_cbus_hwinfo ne2k_cbus_hwinfo_list[] __initdata = {
+#ifdef CONFIG_NE2K_CBUS_ATLA98
+/* NOT TESTED */
+	{
+		NE2K_CBUS_HARDWARE_TYPE_ATLA98,
+		"LA-98-T",
+#ifndef MODULE
+		atla98_portlist,
+#endif
+		&atla98_offsetinfo, atla98_regionlist
+	},
+#endif
+#ifdef CONFIG_NE2K_CBUS_BDN
+/* NOT TESTED */
+	{
+		NE2K_CBUS_HARDWARE_TYPE_BDN,
+		"LD-BDN[123]A",
+#ifndef MODULE
+		bdn_portlist,
+#endif
+		&bdn_offsetinfo, bdn_regionlist
+	},
+#endif
+#ifdef CONFIG_NE2K_CBUS_ICM
+	{
+		NE2K_CBUS_HARDWARE_TYPE_ICM,
+		"IF-27xxET",
+#ifndef MODULE
+		icm_portlist,
+#endif
+		&icm_offsetinfo, icm_regionlist
+	},
+#endif
+#ifdef CONFIG_NE2K_CBUS_NE2K
+	{
+		NE2K_CBUS_HARDWARE_TYPE_NE2K,
+		"NE2000 compat.",
+#ifndef MODULE
+		ne2k_portlist,
+#endif
+		&ne2k_offsetinfo, ne2k_regionlist
+	},
+#endif
+#ifdef CONFIG_NE2K_CBUS_NEC108
+	{
+		NE2K_CBUS_HARDWARE_TYPE_NEC108,
+		"PC-9801-108",
+#ifndef MODULE
+		nec108_portlist,
+#endif
+		&nec108_offsetinfo, nec108_regionlist
+	},
+#endif
+#ifdef CONFIG_NE2K_CBUS_IOLA98
+	{
+		NE2K_CBUS_HARDWARE_TYPE_IOLA98,
+		"LA-98",
+#ifndef MODULE
+		iola98_portlist,
+#endif
+		&iola98_offsetinfo, iola98_regionlist
+	},
+#endif
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+	{
+		NE2K_CBUS_HARDWARE_TYPE_CNET98EL,
+		"C-NET(98)E/L",
+#ifndef MODULE
+		cnet98el_portlist,
+#endif
+		&cnet98el_offsetinfo, cnet98el_regionlist
+	},
+#endif
+/* NOTE: LGY98 must be probed before EGY98, or system stalled!? */
+#ifdef CONFIG_NE2K_CBUS_LGY98
+	{
+		NE2K_CBUS_HARDWARE_TYPE_LGY98,
+		"LGY-98",
+#ifndef MODULE
+		lgy98_portlist,
+#endif
+		&lgy98_offsetinfo, lgy98_regionlist
+	},
+#endif
+#ifdef CONFIG_NE2K_CBUS_EGY98
+	{
+		NE2K_CBUS_HARDWARE_TYPE_EGY98,
+		"EGY-98",
+#ifndef MODULE
+		egy98_portlist,
+#endif
+		&egy98_offsetinfo, egy98_regionlist
+	},
+#endif
+	{
+		0,
+		"unsupported hardware",
+#ifndef MODULE
+		NULL,
+#endif
+		NULL, NULL
+	}
+};
+
+static int __init ne2k_cbus_init(struct net_device *dev)
+{
+	struct ei_device *ei_local;
+	if (dev->priv == NULL) {
+		ei_local = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+		if (ei_local == NULL)
+			return -ENOMEM;
+		memset(ei_local, 0, sizeof(struct ei_device));
+		ei_local->reg_offset = kmalloc(sizeof(typeof(*ei_local->reg_offset))*18, GFP_KERNEL);
+		if (ei_local->reg_offset == NULL) {
+			kfree(ei_local);
+			return -ENOMEM;
+		}
+		spin_lock_init(&ei_local->page_lock);
+		dev->priv = ei_local;
+	}
+	return 0;
+}
+
+static void ne2k_cbus_destroy(struct net_device *dev)
+{
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+	if (ei_local != NULL) {
+		if (ei_local->reg_offset)
+			kfree(ei_local->reg_offset);
+		kfree(dev->priv);
+		dev->priv = NULL;
+	}
+}
+
+static const struct ne2k_cbus_hwinfo * __init ne2k_cbus_get_hwinfo(int hwtype)
+{
+	const struct ne2k_cbus_hwinfo *hw;
+
+	for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+		if (hw->hwtype == hwtype) break;
+	}
+	return hw;
+}
+
+static void __init ne2k_cbus_set_hwtype(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr)
+{
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+	int i;
+	int hwtype_old = dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK;
+
+	if (!ei_local)
+		panic("Gieee! ei_local == NULL!! (from %p)",
+		       __builtin_return_address(0));
+
+	dev->mem_start &= ~NE2K_CBUS_HARDWARE_TYPE_MASK;
+	dev->mem_start |= hw->hwtype & NE2K_CBUS_HARDWARE_TYPE_MASK;
+
+	if (ei_debug > 2) {
+		printk(KERN_DEBUG "hwtype changed: %d -> %d\n",hwtype_old,(int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+	}
+
+	if (hw->offsetinfo) {
+		for (i = 0; i < 8; i++) {
+			ei_local->reg_offset[i] = hw->offsetinfo->skip * i;
+		}
+		for (i = 8; i < 16; i++) {
+			ei_local->reg_offset[i] =
+				hw->offsetinfo->skip*(i-8) + hw->offsetinfo->offset8;
+		}
+#ifdef CONFIG_NE2K_CBUS_NEC108
+		if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_NEC108) {
+			int adj = (ioaddr & 0xf000) /2;
+			ei_local->reg_offset[16] = 
+				(hw->offsetinfo->offset10 | adj) - ioaddr;
+			ei_local->reg_offset[17] = 
+				(hw->offsetinfo->offset1f | adj) - ioaddr;
+		} else {
+#endif /* CONFIG_NE2K_CBUS_NEC108 */
+			ei_local->reg_offset[16] = hw->offsetinfo->offset10;
+			ei_local->reg_offset[17] = hw->offsetinfo->offset1f;
+#ifdef CONFIG_NE2K_CBUS_NEC108
+		}
+#endif
+	} else {
+		/* make dummmy offset list */
+		for (i = 0; i < 16; i++) {
+			ei_local->reg_offset[i] = i;
+		}
+		ei_local->reg_offset[16] = 0x10;
+		ei_local->reg_offset[17] = 0x1f;
+	}
+}
+
+#if defined(CONFIG_NE2K_CBUS_ICM) || defined(CONFIG_NE2K_CBUS_CNET98EL)
+static void __init ne2k_cbus_readmem(struct net_device *dev, int ioaddr, unsigned short memaddr, char *buf, unsigned short len)
+{
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+	outb_p(E8390_NODMA | E8390_START, ioaddr+E8390_CMD);
+	outb_p(len & 0xff, ioaddr+EN0_RCNTLO);
+	outb_p(len >> 8, ioaddr+EN0_RCNTHI);
+	outb_p(memaddr & 0xff, ioaddr+EN0_RSARLO);
+	outb_p(memaddr >> 8, ioaddr+EN0_RSARHI);
+	outb_p(E8390_RREAD | E8390_START, ioaddr+E8390_CMD);
+	insw(ioaddr+NE_DATAPORT, buf, len >> 1);
+}
+static void __init ne2k_cbus_writemem(struct net_device *dev, int ioaddr, unsigned short memaddr, const char *buf, unsigned short len)
+{
+	struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+	outb_p(E8390_NODMA | E8390_START, ioaddr+E8390_CMD);
+	outb_p(ENISR_RDC, ioaddr+EN0_ISR);
+	outb_p(len & 0xff, ioaddr+EN0_RCNTLO);
+	outb_p(len >> 8, ioaddr+EN0_RCNTHI);
+	outb_p(memaddr & 0xff, ioaddr+EN0_RSARLO);
+	outb_p(memaddr >> 8, ioaddr+EN0_RSARHI);
+	outb_p(E8390_RWRITE | E8390_START, ioaddr+E8390_CMD);
+	outsw(ioaddr+NE_DATAPORT, buf, len >> 1);
+}
+#endif
+
+static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr);
+/* End of ne2k_cbus.h */
diff -urN linux-2.5.65-bk1/drivers/net/ppp_generic.c linux-2.5.65-bk2/drivers/net/ppp_generic.c
--- linux-2.5.65-bk1/drivers/net/ppp_generic.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/drivers/net/ppp_generic.c	Mon Mar 31 12:39:50 2003
@@ -2214,6 +2214,11 @@
  * and for initialization.
  */
 
+static void ppp_device_destructor(struct net_device *dev)
+{
+	kfree(dev);
+}
+
 /*
  * Create a new ppp interface unit.  Fails if it can't allocate memory
  * or if there is already a unit with the requested number.
@@ -2262,7 +2267,7 @@
 	dev->init = ppp_net_init;
 	sprintf(dev->name, "ppp%d", unit);
 	dev->priv = ppp;
-	dev->features |= NETIF_F_DYNALLOC;
+	dev->destructor = ppp_device_destructor;
 
 	rtnl_lock();
 	ret = register_netdevice(dev);
diff -urN linux-2.5.65-bk1/drivers/net/tg3.c linux-2.5.65-bk2/drivers/net/tg3.c
--- linux-2.5.65-bk1/drivers/net/tg3.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/drivers/net/tg3.c	Mon Mar 31 12:39:50 2003
@@ -55,8 +55,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.4c"
-#define DRV_MODULE_RELDATE	"Feb 18, 2003"
+#define DRV_MODULE_VERSION	"1.5"
+#define DRV_MODULE_RELDATE	"March 21, 2003"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -6581,11 +6581,11 @@
 
 	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
 
+	ret = 0;
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
-		return 0;
+		goto out;
 
-	ret = 0;
 	while (1) {
 		u32 *p, i;
 
diff -urN linux-2.5.65-bk1/drivers/pnp/pnpbios/core.c linux-2.5.65-bk2/drivers/pnp/pnpbios/core.c
--- linux-2.5.65-bk1/drivers/pnp/pnpbios/core.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/drivers/pnp/pnpbios/core.c	Mon Mar 31 12:39:50 2003
@@ -322,7 +322,7 @@
 	u16 status;
 	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	if ( !boot & pnpbios_dont_use_current_config )
+	if ( !boot && pnpbios_dont_use_current_config )
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0,
 			       nodenum, sizeof(char), data, 65536);
@@ -350,7 +350,7 @@
 	u16 status;
 	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	if ( !boot & pnpbios_dont_use_current_config )
+	if ( !boot && pnpbios_dont_use_current_config )
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0,
 			       data, 65536, 0, 0);
diff -urN linux-2.5.65-bk1/drivers/scsi/3w-xxxx.c linux-2.5.65-bk2/drivers/scsi/3w-xxxx.c
--- linux-2.5.65-bk1/drivers/scsi/3w-xxxx.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/drivers/scsi/3w-xxxx.c	Mon Mar 31 12:39:50 2003
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2002 3ware Inc.
+   Copyright (C) 1999-2003 3ware Inc.
 
    Kernel compatiblity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -164,6 +164,11 @@
                  Add support for mode sense opcode.
                  Add support for cache mode page.
                  Add support for synchronize cache opcode.
+   1.02.00.032 - Fix small multicard rollcall bug.
+                 Make driver stay loaded with no units for hot add/swap.
+                 Add support for "twe" character device for ioctls.
+                 Clean up request_id queueing code.
+                 Fix tw_scsi_queue() spinlocks.
 */
 
 #include <linux/module.h>
@@ -203,6 +208,9 @@
 
 #include "3w-xxxx.h"
 
+static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int tw_chrdev_open(struct inode *inode, struct file *file);
+static int tw_chrdev_release(struct inode *inode, struct file *file);
 static int tw_copy_info(TW_Info *info, char *fmt, ...);
 static void tw_copy_mem_info(TW_Info *info, char *data, int len);
 static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -216,10 +224,19 @@
 	tw_halt, NULL, 0
 };
 
+/* File operations struct for character device */
+static struct file_operations tw_fops = {
+	owner: THIS_MODULE,
+	ioctl: tw_chrdev_ioctl,
+	open: tw_chrdev_open,
+	release: tw_chrdev_release
+};
+
 /* Globals */
-char *tw_driver_version="1.02.00.031";
+char *tw_driver_version="1.02.00.032";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
+static int twe_major = -1;
 
 /* Functions */
 
@@ -599,6 +616,209 @@
 	return 0;
 } /* End tw_check_errors() */
 
+/* This function handles ioctl for the character device */
+static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int error, request_id;
+	dma_addr_t dma_handle;
+	unsigned short tw_aen_code;
+	struct timeval before, timeout;
+	unsigned long flags = 0x0;
+	unsigned int data_buffer_length = 0;
+	unsigned long data_buffer_length_adjusted = 0;
+	unsigned long *cpu_addr;
+	TW_New_Ioctl *tw_ioctl;
+	TW_Passthru *passthru;
+	TW_Device_Extension *tw_dev = tw_device_extension_list[minor(inode->i_rdev)];
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");
+
+	/* Only let one of these through at a time */
+	if (test_and_set_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags)) {
+		return -EBUSY;
+	}
+
+	/* First copy down the buffer length */
+	error = copy_from_user(&data_buffer_length, (void *)arg, sizeof(unsigned int));
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying buffer length from userspace.\n");
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -EFAULT;
+	}
+
+	/* Check size */
+	if (data_buffer_length > TW_MAX_SECTORS * 512) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Invalid buffer size (%d).\n", data_buffer_length);
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -EFAULT;
+	}
+
+	/* Hardware can only do multiple of 512 byte transfers */
+	if (data_buffer_length % 512)
+		data_buffer_length_adjusted = data_buffer_length + 512 - (data_buffer_length % 512);
+	else
+		data_buffer_length_adjusted = data_buffer_length;
+
+	/* Now allocate ioctl buf memory */
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle);
+	if (cpu_addr == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error allocating memory.\n");
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -ENOMEM;
+	}
+
+	tw_ioctl = (TW_New_Ioctl *)cpu_addr;
+
+	/* Now copy down the entire ioctl */
+	error = copy_from_user(tw_ioctl, (void *)arg, data_buffer_length + sizeof(TW_New_Ioctl) - 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying data from userspace.\n");
+		pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -EFAULT;
+	}
+
+	passthru = (TW_Passthru *)&tw_ioctl->firmware_command;
+
+	/* See which ioctl we are doing */
+	switch (cmd) {
+		case TW_OP_NOP:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_OP_NOP.\n");
+			break;
+		case TW_OP_AEN_LISTEN:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n");
+			memset(tw_ioctl->data_buffer, 0, tw_ioctl->data_buffer_length);
+			if (tw_dev->aen_head == tw_dev->aen_tail) {
+				tw_aen_code = TW_AEN_QUEUE_EMPTY;
+			} else {
+				tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];
+				if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+					tw_dev->aen_head = TW_Q_START;
+				} else {
+					tw_dev->aen_head = tw_dev->aen_head + 1;
+				}
+			}
+			memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code));
+			break;
+		case TW_CMD_PACKET_WITH_DATA:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
+			spin_lock_irqsave(&tw_dev->tw_lock, flags);
+
+			tw_state_request_start(tw_dev, &request_id);
+
+			/* Flag internal command */
+			tw_dev->srb[request_id] = 0;
+
+			/* Flag chrdev ioctl */
+			tw_dev->chrdev_request_id = request_id;
+
+			tw_ioctl->firmware_command.request_id = request_id;
+
+			/* Load the sg list */
+			switch (tw_ioctl->firmware_command.byte0.sgl_offset) {
+			case 2:
+				tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted;
+				break;
+			case 3:
+				tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted;
+				break;
+			case 5:
+				passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				passthru->sg_list[0].length = data_buffer_length_adjusted;
+				break;
+			}
+
+			memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command));
+
+			/* Now post the command packet to the controller */
+			tw_post_command_packet(tw_dev, request_id);
+			spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+
+			/* Now wait for the command to complete */
+			do_gettimeofday(&before);
+
+	tw_ioctl_chrdev_retry:
+
+			if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
+				interruptible_sleep_on_timeout(&tw_dev->ioctl_wqueue, 1);
+				do_gettimeofday(&timeout);
+				if (before.tv_sec + TW_IOCTL_CHRDEV_TIMEOUT < timeout.tv_sec) {
+					/* Now we need to reset the board */
+					printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
+					spin_lock_irqsave(&tw_dev->tw_lock, flags);
+					tw_dev->state[request_id] = TW_S_COMPLETED;
+					tw_state_request_finish(tw_dev, request_id);
+					pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+					tw_dev->posted_request_count--;
+					if (tw_reset_device_extension(tw_dev)) {
+						printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
+					}
+					spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+					clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+					if (signal_pending(current))
+						return -EINTR;
+					else
+						return -EIO;
+				} else {
+					goto tw_ioctl_chrdev_retry;
+				}
+			}
+
+			/* Now copy in the command packet response */
+			memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
+
+			/* Now complete the io */
+			spin_lock_irqsave(&tw_dev->tw_lock, flags);
+			tw_dev->posted_request_count--;
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
+			spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+			break;
+		default:
+			printk(KERN_WARNING "3w-xxxx: Unknown chrdev ioctl 0x%x.\n", cmd);
+	}
+
+	/* Now copy the response to userspace */
+	error = copy_to_user((void *)arg, tw_ioctl, sizeof(TW_New_Ioctl) + tw_ioctl->data_buffer_length - 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying data to userspace.\n");
+		pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -EFAULT;
+	}
+
+	/* Now free ioctl buf memory */
+	pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+
+	clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+
+	return 0;
+} /* End tw_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int tw_chrdev_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor_number;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n");
+
+	minor_number = minor(inode->i_rdev);
+	if (minor_number >= tw_device_extension_count)
+		return -ENODEV;
+
+	return 0;
+} /* End tw_chrdev_open() */
+
+/* This function handles close for the character device */
+static int tw_chrdev_release(struct inode *inode, struct file *file)
+{
+	dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_release()\n");
+
+	return 0;
+} /* End tw_chrdev_release() */
+
 /* This function will clear all interrupts on the controller */
 void tw_clear_all_interrupts(TW_Device_Extension *tw_dev)
 {
@@ -867,7 +1087,9 @@
 
 			/* Disable interrupts on the card */
 			tw_disable_interrupts(tw_dev);
-			
+
+			tries = 0;
+
 			while (tries < TW_MAX_RESET_TRIES) {
 				/* Do soft reset */
 				tw_soft_reset(tw_dev);
@@ -897,8 +1119,8 @@
 				continue;
 			}
 
-			/* Make sure that io region isn't already taken */
-			if (check_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE)) {
+			/* Reserve the io address space */
+			if (!request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME)) {
 				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
 				       (tw_dev->tw_pci_dev->resource[0].start), 
 				       (tw_dev->tw_pci_dev->resource[0].start) + 
@@ -907,16 +1129,10 @@
 				kfree(tw_dev);
 				continue;
 			}
-    
-			/* Reserve the io address space */
-			request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
+
 			error = tw_initialize_units(tw_dev);
 			if (error) {
 				printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", j);
-				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-				tw_free_device_extension(tw_dev);
-				kfree(tw_dev);
-				continue;
 			}
 
 			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
@@ -935,7 +1151,7 @@
 			if (tw_dev->num_units > 0) {
 				/* Use SHT cmd_per_lun here */
 				tw_dev->free_head = TW_Q_START;
-				tw_dev->free_tail = TW_Q_LENGTH - 1;
+				tw_dev->free_tail = TW_Q_START;
 				tw_dev->free_wrap = TW_Q_LENGTH - 1;
 			}
 
@@ -992,13 +1208,7 @@
 			/* Tell the firmware we support shutdown notification*/
 			error = tw_setfeature(tw_dev2, 2, 1, &c);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Error setting features for card %d.\n", j);
-				scsi_unregister(host);
-				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-				tw_free_device_extension(tw_dev);
-				kfree(tw_dev);
-				numcards--;
-				continue;
+				printk(KERN_WARNING "3w-xxxx: Unable to set features for card %d, old firmware or card.\n", j);
 			}
 
 			/* Now setup the interrupt handler */
@@ -1023,10 +1233,14 @@
 		}
 	}
 
-	if (numcards == 0) 
-		printk(KERN_WARNING "3w-xxxx: No cards with valid units found.\n");
-	else
-	  register_reboot_notifier(&tw_notifier);
+	if (numcards == 0) {
+		printk(KERN_WARNING "3w-xxxx: No cards found.\n");
+	} else {
+		register_reboot_notifier(&tw_notifier);
+		if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0) {
+			printk(KERN_WARNING "3w-xxxx: Unable to register \"twe\" character device, error = %d.\n", twe_major);
+		}
+	}
 
 	return numcards;
 } /* End tw_findcards() */
@@ -1153,6 +1367,8 @@
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
 	spin_lock_init(&tw_dev->tw_lock);
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+	init_waitqueue_head(&tw_dev->ioctl_wqueue);
 
 	return 0;
 } /* End tw_initialize_device_extension() */
@@ -1395,9 +1611,14 @@
 				/* Check for internal command completion */
 				if (tw_dev->srb[request_id] == 0) {
 					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
-					retval = tw_aen_complete(tw_dev, request_id);
-					if (retval) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
+					/* Check for chrdev ioctl completion */
+					if (request_id != tw_dev->chrdev_request_id) {
+						retval = tw_aen_complete(tw_dev, request_id);
+						if (retval) {
+							printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
+						}
+					} else {
+						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 					}
 				} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
@@ -1409,6 +1630,10 @@
 					case WRITE_6:
 						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
 						break;
+					case TEST_UNIT_READY:
+						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
+						error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
+						break;
 					case INQUIRY:
 						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
 						error = tw_scsiop_inquiry_complete(tw_dev, request_id);
@@ -2070,12 +2295,13 @@
 		tw_dev->state[i] = TW_S_INITIAL;
 	}
 	tw_dev->free_head = TW_Q_START;
-	tw_dev->free_tail = TW_Q_LENGTH - 1;
+	tw_dev->free_tail = TW_Q_START;
 	tw_dev->posted_request_count = 0;
 	tw_dev->pending_request_count = 0;
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
 	tw_dev->reset_print = 0;
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
 	return 0;
 } /* End tw_reset_device_extension() */
@@ -2357,7 +2583,6 @@
 	unsigned char *command = SCpnt->cmnd;
 	int request_id = 0;
 	int error = 0;
-	unsigned long flags = 0;
 	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
 
 	if (tw_dev == NULL) {
@@ -2367,14 +2592,14 @@
 		return 0;
 	}
 
-	spin_lock_irqsave(&tw_dev->tw_lock, flags);
+	spin_lock(&tw_dev->tw_lock);
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
 
 	/* Skip scsi command if it isn't for us */
-	if ((tw_dev->is_unit_present[SCpnt->device->id] == FALSE) || (SCpnt->device->lun != 0)) {
+	if ((SCpnt->device->channel != 0) || (SCpnt->device->lun != 0)) {
 		SCpnt->result = (DID_BAD_TARGET << 16);
 		done(SCpnt);
-		spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+		spin_unlock(&tw_dev->tw_lock);
 		return 0;
 	}
 	
@@ -2387,6 +2612,9 @@
 	/* Save the scsi command for use by the ISR */
 	tw_dev->srb[request_id] = SCpnt;
 
+	/* Initialize phase to zero */
+	SCpnt->SCp.phase = 0;
+
 	switch (*command) {
 		case READ_10:
 		case READ_6:
@@ -2436,7 +2664,7 @@
 		SCpnt->result = (DID_ERROR << 16);
 		done(SCpnt);
 	}
-	spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+	spin_unlock(&tw_dev->tw_lock);
 
 	return 0;
 } /* End tw_scsi_queue() */
@@ -2460,6 +2688,12 @@
 	/* Free up the IRQ */
 	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
 
+	/* Unregister character device */
+	if (twe_major >= 0) {
+		unregister_chrdev(twe_major, "twe");
+		twe_major = -1;
+	}
+
 	/* Free up device extension resources */
 	tw_free_device_extension(tw_dev);
 
@@ -2533,7 +2767,6 @@
 {
 	unsigned char *is_unit_present;
 	unsigned char *request_buffer;
-	int i;
 	TW_Param *param;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
@@ -2545,12 +2778,12 @@
 	}
 	request_buffer = tw_dev->srb[request_id]->request_buffer;
 	memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
-	request_buffer[0] = TYPE_DISK;									 /* Peripheral device type */
-	request_buffer[1] = 0;													 /* Device type modifier */
-	request_buffer[2] = 0;													 /* No ansi/iso compliance */
-	request_buffer[4] = 31;													/* Additional length */
+	request_buffer[0] = TYPE_DISK; /* Peripheral device type */
+	request_buffer[1] = 0;	       /* Device type modifier */
+	request_buffer[2] = 0;	       /* No ansi/iso compliance */
+	request_buffer[4] = 31;	       /* Additional length */
 	memcpy(&request_buffer[8], "3ware   ", 8);	 /* Vendor ID */
-	memcpy(&request_buffer[16], "3w-xxxx         ", 16); /* Product ID */
+	sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id);
 	memcpy(&request_buffer[32], tw_driver_version, 3);
 
 	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -2560,15 +2793,12 @@
 	}
 	is_unit_present = &(param->data[0]);
 
-	for (i=0 ; i<TW_MAX_UNITS; i++) {
-		if (is_unit_present[i] == 0) {
-			tw_dev->is_unit_present[i] = FALSE;
-		} else {
-		  if (is_unit_present[i] & TW_UNIT_ONLINE) {
-			tw_dev->is_unit_present[i] = TRUE;
-			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete: Unit %d found.\n", i);
-		  }
-		}
+	if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = TRUE;
+	} else {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = FALSE;
+		tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+		return TW_ISR_DONT_RESULT;
 	}
 
 	return 0;
@@ -2946,17 +3176,88 @@
 /* This function will handle test unit ready scsi command */
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
 {
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	u32 command_que_addr;
+	unsigned long param_value;
+
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
 
-	/* Tell the scsi layer were done */
-	tw_dev->state[request_id] = TW_S_COMPLETED;
-	tw_state_request_finish(tw_dev, request_id);
-	tw_dev->srb[request_id]->result = (DID_OK << 16);
-	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+	/* Initialize command packet */
+	command_que_addr = tw_dev->registers.command_que_addr;
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n");
+		return 1;
+	}
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->byte0.opcode = TW_OP_GET_PARAM;
+	command_packet->byte0.sgl_offset = 2;
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->byte3.unit = 0;
+	command_packet->byte3.host_id = 0;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+
+	/* Now setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = 3;	 /* unit summary table */
+	param->parameter_id = 3; /* unitsstatus parameter */
+	param->parameter_size_bytes = TW_MAX_UNITS;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n");
+		return 1;
+	}
+
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
 
 	return 0;
 } /* End tw_scsiop_test_unit_ready() */
 
+/* This function is called by the isr to complete a testunitready command */
+int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	unsigned char *is_unit_present;
+	TW_Param *param;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n");
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	is_unit_present = &(param->data[0]);
+
+	if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = TRUE;
+	} else {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = FALSE;
+		tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+		return TW_ISR_DONT_RESULT;
+	}
+
+	return 0;
+} /* End tw_scsiop_test_unit_ready_complete() */
+
 /* Set a value in the features table */
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
                   unsigned char *val)
@@ -3091,17 +3392,13 @@
 {
 	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish()\n");
   
-	do {    
-		if (tw_dev->free_tail == tw_dev->free_wrap) {
-			tw_dev->free_tail = TW_Q_START;
-		} else {
-			tw_dev->free_tail = tw_dev->free_tail + 1;
-		}
-	} while ((tw_dev->state[tw_dev->free_queue[tw_dev->free_tail]] != TW_S_COMPLETED));
-
 	tw_dev->free_queue[tw_dev->free_tail] = request_id;
-
 	tw_dev->state[request_id] = TW_S_FINISHED;
+	if (tw_dev->free_tail == tw_dev->free_wrap)
+		tw_dev->free_tail = TW_Q_START;
+	else
+		tw_dev->free_tail++;
+
 	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish(): Freeing request_id %d\n", request_id);
 
 	return 0;
@@ -3115,20 +3412,16 @@
 	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
 	
 	/* Obtain next free request_id */
-	do {
-		if (tw_dev->free_head == tw_dev->free_wrap) {
-			tw_dev->free_head = TW_Q_START;
-		} else {
-			tw_dev->free_head = tw_dev->free_head + 1;
-		}
-	} while (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] & TW_START_MASK);
-
 	id = tw_dev->free_queue[tw_dev->free_head];
+	if (tw_dev->free_head == tw_dev->free_wrap)
+		tw_dev->free_head = TW_Q_START;
+	else
+		tw_dev->free_head++;
 
-	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id);
 	*request_id = id;
 	tw_dev->state[id] = TW_S_STARTED;
 
+	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id);
 	return 0;
 } /* End tw_state_request_start() */
 
diff -urN linux-2.5.65-bk1/drivers/scsi/3w-xxxx.h linux-2.5.65-bk2/drivers/scsi/3w-xxxx.h
--- linux-2.5.65-bk1/drivers/scsi/3w-xxxx.h	Mon Mar 17 13:43:48 2003
+++ linux-2.5.65-bk2/drivers/scsi/3w-xxxx.h	Mon Mar 31 12:39:50 2003
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2002 3ware Inc.
+   Copyright (C) 1999-2003 3ware Inc.
 
    Kernel compatiblity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -113,11 +113,11 @@
   {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
   {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
   {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+  {0x37, 0x02, 0x04, 0x00}, // Unit offline                 Not ready
 
   /* Codes for older firmware */
                             // 3ware Error                  SCSI Error
   {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
-  {0x37, 0x0b, 0x04, 0x00}, // Unit offline                 Logical unit not ready
   {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
 };
 
@@ -219,18 +219,23 @@
 #define TW_MAX_PCI_BUSES		      255
 #define TW_MAX_RESET_TRIES		      3
 #define TW_UNIT_INFORMATION_TABLE_BASE	      0x300
-#define TW_MAX_CMDS_PER_LUN		      255
+#define TW_MAX_CMDS_PER_LUN		      254 /* 254 for io, 1 for
+                                                     chrdev ioctl, one for
+                                                     internal aen post */
 #define TW_BLOCK_SIZE			      0x200 /* 512-byte blocks */
 #define TW_IOCTL                              0x80
 #define TW_UNIT_ONLINE                        1
 #define TW_IN_INTR                            1
 #define TW_IN_IOCTL                           2
+#define TW_IN_CHRDEV_IOCTL                    3
 #define TW_MAX_SECTORS                        256
 #define TW_AEN_WAIT_TIME                      1000
 #define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
 #define TW_ISR_DONT_COMPLETE                  2
 #define TW_ISR_DONT_RESULT                    3
 #define TW_IOCTL_TIMEOUT                      25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_TIMEOUT               25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_FREE                  -1
 
 /* Macros */
 #define TW_STATUS_ERRORS(x) \
@@ -246,6 +251,8 @@
 #define dprintk(msg...) do { } while(0)
 #endif
 
+#pragma pack(1)
+
 /* Scatter Gather List Entry */
 typedef struct TAG_TW_SG_Entry {
 	u32 address;
@@ -295,6 +302,8 @@
 	} byte8;
 } TW_Command;
 
+#pragma pack()
+
 typedef struct TAG_TW_Ioctl {
 	unsigned char opcode;
 	unsigned short table_id;
@@ -304,6 +313,16 @@
 	unsigned char data[1];
 } TW_Ioctl;
 
+#pragma pack(1)
+
+/* Structure for new chardev ioctls */
+typedef struct TAG_TW_New_Ioctl {
+	unsigned int data_buffer_length;
+	unsigned char padding [508];
+	TW_Command firmware_command;
+	char data_buffer[1];
+} TW_New_Ioctl;
+
 /* GetParam descriptor */
 typedef struct {
 	unsigned short	table_id;
@@ -414,8 +433,12 @@
 	unsigned long		*ioctl_data[TW_Q_LENGTH];
 	int			reset_print;
 	char                    online;
+	volatile int		chrdev_request_id;
+	wait_queue_head_t	ioctl_wqueue;
 } TW_Device_Extension;
 
+#pragma pack()
+
 /* Function prototypes */
 int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
@@ -463,6 +486,7 @@
 int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, 
 		  unsigned char *val);
 int tw_setup_irq(TW_Device_Extension *tw_dev);
@@ -483,9 +507,10 @@
 	.eh_abort_handler	= tw_scsi_eh_abort,	\
 	.eh_host_reset_handler	= tw_scsi_eh_reset,	\
 	.bios_param	= tw_scsi_biosparam,		\
-	.can_queue	= TW_Q_LENGTH-1,		\
+	.can_queue	= TW_Q_LENGTH-2,		\
 	.this_id	= -1,				\
 	.sg_tablesize	= TW_MAX_SGL_LENGTH,		\
+	.max_sectors    = TW_MAX_SECTORS,		\
 	.cmd_per_lun	= TW_MAX_CMDS_PER_LUN,		\
 	.present	= 0,				\
 	.unchecked_isa_dma	= 0,			\
diff -urN linux-2.5.65-bk1/drivers/scsi/53c7xx.c linux-2.5.65-bk2/drivers/scsi/53c7xx.c
--- linux-2.5.65-bk1/drivers/scsi/53c7xx.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/drivers/scsi/53c7xx.c	Mon Mar 31 12:39:50 2003
@@ -1463,9 +1463,9 @@
     patch_abs_32 (hostdata->script, 0, test_src, 
 	virt_to_bus(&hostdata->test_source));
     patch_abs_32 (hostdata->script, 0, saved_dsa,
-	virt_to_bus(&hostdata->saved2_dsa));
+	virt_to_bus((void *)&hostdata->saved2_dsa));
     patch_abs_32 (hostdata->script, 0, emulfly,
-	virt_to_bus(&hostdata->emulated_intfly));
+	virt_to_bus((void *)&hostdata->emulated_intfly));
 
     patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect, 
 	(unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
@@ -1759,7 +1759,7 @@
 static void 
 NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
     Scsi_Cmnd *c = cmd->cmd;
-    struct Scsi_Host *host = c->host;
+    struct Scsi_Host *host = c->device->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
     	host->hostdata[0];
     int i;
@@ -1784,18 +1784,18 @@
      */
 
     patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
-    	dsa_temp_lun, c->lun);
+    	dsa_temp_lun, c->device->lun);
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
 	dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr));
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
     	dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero -
 	Ent_dsa_code_template + A_dsa_next);
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), 
-    	dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->target].script));
+    	dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->device->id].script));
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), 
-    	dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->target].sscf_710));
+    	dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->device->id].sscf_710));
     patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
-    	    dsa_temp_target, 1 << c->target);
+    	    dsa_temp_target, 1 << c->device->id);
     /* XXX - new pointer stuff */
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
     	dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer));
@@ -1856,7 +1856,7 @@
 static void 
 abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
     Scsi_Cmnd *c = cmd->cmd;
-    struct Scsi_Host *host = c->host;
+    struct Scsi_Host *host = c->device->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
     	host->hostdata[0];
     unsigned long flags;
@@ -1940,7 +1940,7 @@
 	    host->host_no, c->pid);
     else if (linux_search) {
 	*linux_prev = linux_search->next;
-	--hostdata->busy[c->target][c->lun];
+	--hostdata->busy[c->device->id][c->device->lun];
     }
 
     /* Return the NCR command structure to the free list */
@@ -2287,9 +2287,9 @@
 	    hostdata->dsp_changed = 1;
 	    if (cmd && (cmd->flags & CMD_FLAG_SDTR)) {
 		printk ("scsi%d : target %d rejected SDTR\n", host->host_no, 
-		    c->target);
+		    c->device->id);
 		cmd->flags &= ~CMD_FLAG_SDTR;
-		asynchronous (host, c->target);
+		asynchronous (host, c->device->id);
 		print = 0;
 	    } 
 	    break;
@@ -2311,7 +2311,7 @@
 	if (print) {
 	    printk ("scsi%d : received message", host->host_no);
 	    if (c) 
-	    	printk (" from target %d lun %d ", c->target, c->lun);
+	    	printk (" from target %d lun %d ", c->device->id, c->device->lun);
 	    print_msg ((unsigned char *) hostdata->msg_buf);
 	    printk("\n");
 	}
@@ -2331,7 +2331,7 @@
 
 	if (cmd) {
 	    char buf[80];
-	    sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->target,
+	    sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->device->id,
 		(cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting");
 	    print_synchronous (buf, (unsigned char *) hostdata->msg_buf);
 
@@ -2346,10 +2346,10 @@
 	    if (cmd->flags & CMD_FLAG_SDTR) {
 		cmd->flags &= ~CMD_FLAG_SDTR; 
 		if (hostdata->msg_buf[4]) 
-		    synchronous (host, c->target, (unsigned char *) 
+		    synchronous (host, c->device->id, (unsigned char *) 
 		    	hostdata->msg_buf);
 		else 
-		    asynchronous (host, c->target);
+		    asynchronous (host, c->device->id);
 		hostdata->dsp = hostdata->script + hostdata->E_accept_message /
 		    sizeof(u32);
 		hostdata->dsp_changed = 1;
@@ -2357,11 +2357,11 @@
 	    } else {
 		if (hostdata->options & OPTION_SYNCHRONOUS)  {
 		    cmd->flags |= CMD_FLAG_DID_SDTR;
-		    synchronous (host, c->target, (unsigned char *) 
+		    synchronous (host, c->device->id, (unsigned char *) 
 			hostdata->msg_buf);
 		} else {
 		    hostdata->msg_buf[4] = 0;		/* 0 offset = async */
-		    asynchronous (host, c->target);
+		    asynchronous (host, c->device->id);
 		}
 		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
 		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32) 
@@ -2545,9 +2545,9 @@
 		    host->host_no, NCR53c7x0_read8(SXFER_REG));
 	    if (c) {
 		print_insn (host, (u32 *) 
-		    hostdata->sync[c->target].script, "", 1);
+		    hostdata->sync[c->device->id].script, "", 1);
 		print_insn (host, (u32 *) 
-		    hostdata->sync[c->target].script + 2, "", 1);
+		    hostdata->sync[c->device->id].script + 2, "", 1);
 	    }
 	}
     	return SPECIFIC_INT_RESTART;
@@ -2658,7 +2658,7 @@
 	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
 	    if (c)
 		printk("scsi%d : target %d lun %d disconnecting\n", 
-		    host->host_no, c->target, c->lun);
+		    host->host_no, c->device->id, c->device->lun);
 	    else
 		printk("scsi%d : unknown target disconnecting\n",
 		    host->host_no);
@@ -2680,9 +2680,9 @@
 #endif
 	    if (c) {
 		print_insn (host, (u32 *) 
-		    hostdata->sync[c->target].script, "", 1);
+		    hostdata->sync[c->device->id].script, "", 1);
 		print_insn (host, (u32 *) 
-		    hostdata->sync[c->target].script + 2, "", 1);
+		    hostdata->sync[c->device->id].script + 2, "", 1);
 	    }
 	}
 	return SPECIFIC_INT_RESTART;
@@ -2734,8 +2734,8 @@
 	    if ((hostdata->chip / 100) == 8) {
 		scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800);
 		if (c) {
-		  if (sxfer != hostdata->sync[c->target].sxfer_sanity ||
-		    scntl3 != hostdata->sync[c->target].scntl3_sanity) {
+		  if (sxfer != hostdata->sync[c->device->id].sxfer_sanity ||
+		    scntl3 != hostdata->sync[c->device->id].scntl3_sanity) {
 		   	printk ("scsi%d :  sync sanity check failed sxfer=0x%x, scntl3=0x%x",
 			    host->host_no, sxfer, scntl3);
 			NCR53c7x0_write8 (SXFER_REG, sxfer);
@@ -2746,12 +2746,12 @@
 		    host->host_no, (int) sxfer, (int) scntl3);
 	    } else {
 		if (c) {
-		  if (sxfer != hostdata->sync[c->target].sxfer_sanity) {
+		  if (sxfer != hostdata->sync[c->device->id].sxfer_sanity) {
 		   	printk ("scsi%d :  sync sanity check failed sxfer=0x%x",
 			    host->host_no, sxfer);
 			NCR53c7x0_write8 (SXFER_REG, sxfer);
 			NCR53c7x0_write8 (SBCL_REG,
-				hostdata->sync[c->target].sscf_710);
+				hostdata->sync[c->device->id].sscf_710);
 		    }
 		} else 
     	    	  printk ("scsi%d : unknown command sxfer=0x%x\n",
@@ -2807,9 +2807,9 @@
 			(DCMD_REG)) == hostdata->script + 
 		    	Ent_select_check_dsa / sizeof(u32) ?
 		    "selection" : "reselection";
-		if (c && sdid != c->target) {
+		if (c && sdid != c->device->id) {
 		    printk ("scsi%d : SDID target %d != DSA target %d at %s\n",
-			host->host_no, sdid, c->target, where);
+			host->host_no, sdid, c->device->id, where);
 		    print_lots(host);
 		    dump_events (host, 20);
 		    return SPECIFIC_INT_PANIC;
@@ -2855,7 +2855,7 @@
 		if (event->event == EVENT_RESELECT)
 		    event->lun = hostdata->reselected_identify & 0xf;
 		else if (c)
-		    event->lun = c->lun;
+		    event->lun = c->device->lun;
 		else
 		    event->lun = 255;
 		do_gettimeofday(&(event->time));
@@ -3049,7 +3049,7 @@
 
 static struct NCR53c7x0_cmd *
 allocate_cmd (Scsi_Cmnd *cmd) {
-    struct Scsi_Host *host = cmd->host;
+    struct Scsi_Host *host = cmd->device->host;
     struct NCR53c7x0_hostdata *hostdata = 
 	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     u32 real;			/* Real address */
@@ -3061,8 +3061,8 @@
 	printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
 		"         target = %d, lun = %d, %s\n",
 	    host->host_no, hostdata->num_cmds, host->can_queue,
-	    cmd->target, cmd->lun, (hostdata->cmd_allocated[cmd->target] &
-		(1 << cmd->lun)) ? "already allocated" : "not allocated");
+	    cmd->device->id, cmd->device->lun, (hostdata->cmd_allocated[cmd->device->id] &
+		(1 << cmd->device->lun)) ? "already allocated" : "not allocated");
 
 /*
  * If we have not yet reserved commands for this I_T_L nexus, and
@@ -3070,11 +3070,11 @@
  * being allocated under 1.3.x, or being outside of scan_scsis in
  * 1.2.x), do so now.
  */
-    if (!(hostdata->cmd_allocated[cmd->target] & (1 << cmd->lun)) &&
+    if (!(hostdata->cmd_allocated[cmd->device->id] & (1 << cmd->device->lun)) &&
 				cmd->device && cmd->device->has_cmdblocks) {
       if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
           hostdata->extra_allocate += host->cmd_per_lun;
-      hostdata->cmd_allocated[cmd->target] |= (1 << cmd->lun);
+      hostdata->cmd_allocated[cmd->device->id] |= (1 << cmd->device->lun);
     }
 
     for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate, 
@@ -3130,7 +3130,7 @@
     local_irq_restore(flags);
     if (!tmp)
 	printk ("scsi%d : can't allocate command for target %d lun %d\n",
-	    host->host_no, cmd->target, cmd->lun);
+	    host->host_no, cmd->device->id, cmd->device->lun);
     return tmp;
 }
 
@@ -3150,7 +3150,7 @@
 static struct NCR53c7x0_cmd *
 create_cmd (Scsi_Cmnd *cmd) {
     NCR53c7x0_local_declare();
-    struct Scsi_Host *host = cmd->host;
+    struct Scsi_Host *host = cmd->device->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
         host->hostdata[0];	
     struct NCR53c7x0_cmd *tmp; 	/* NCR53c7x0_cmd structure for this command */
@@ -3166,7 +3166,7 @@
 #endif
     unsigned long flags;
     u32 exp_select_indirect;	/* Used in sanity check */
-    NCR53c7x0_local_setup(cmd->host);
+    NCR53c7x0_local_setup(cmd->device->host);
 
     if (!(tmp = allocate_cmd (cmd)))
 	return NULL;
@@ -3322,45 +3322,45 @@
 
     if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
 
-	exp_select_indirect = ((1 << cmd->target) << 16) |
-			(hostdata->sync[cmd->target].sxfer_sanity << 8);
+	exp_select_indirect = ((1 << cmd->device->id) << 16) |
+			(hostdata->sync[cmd->device->id].sxfer_sanity << 8);
 
-	if (hostdata->sync[cmd->target].select_indirect != 
+	if (hostdata->sync[cmd->device->id].select_indirect !=
 				exp_select_indirect) {
 	    printk ("scsi%d :  sanity check failed select_indirect=0x%x\n",
-		host->host_no, hostdata->sync[cmd->target].select_indirect);
+		host->host_no, hostdata->sync[cmd->device->id].select_indirect);
 	    FATAL(host);
 
 	}
     }
 
     patch_dsa_32(tmp->dsa, dsa_select, 0,
-		hostdata->sync[cmd->target].select_indirect);
+		hostdata->sync[cmd->device->id].select_indirect);
 
     /*
      * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
      * different commands; although it should be trivial to do them
      * both at the same time.
      */
-    if (hostdata->initiate_wdtr & (1 << cmd->target)) {
+    if (hostdata->initiate_wdtr & (1 << cmd->device->id)) {
 	memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
 	    sizeof(wdtr_message));
     	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
 	local_irq_save(flags);
-	hostdata->initiate_wdtr &= ~(1 << cmd->target);
+	hostdata->initiate_wdtr &= ~(1 << cmd->device->id);
 	local_irq_restore(flags);
-    } else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
+    } else if (hostdata->initiate_sdtr & (1 << cmd->device->id)) {
 	memcpy ((void *) (tmp->select + 1), (void *) sdtr_message, 
 	    sizeof(sdtr_message));
     	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
 	tmp->flags |= CMD_FLAG_SDTR;
 	local_irq_save(flags);
-	hostdata->initiate_sdtr &= ~(1 << cmd->target);
+	hostdata->initiate_sdtr &= ~(1 << cmd->device->id);
 	local_irq_restore(flags);
     
     }
 #if 1
-    else if (!(hostdata->talked_to & (1 << cmd->target)) && 
+    else if (!(hostdata->talked_to & (1 << cmd->device->id)) &&
 		!(hostdata->options & OPTION_NO_ASYNC)) {
 
 	memcpy ((void *) (tmp->select + 1), (void *) async_message, 
@@ -3372,9 +3372,9 @@
     else 
     	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
 
-    hostdata->talked_to |= (1 << cmd->target);
+    hostdata->talked_to |= (1 << cmd->device->id);
     tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ? 
-	IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
+	IDENTIFY (1, cmd->device->lun) : IDENTIFY (0, cmd->device->lun);
     patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
     patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
     patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(tmp->cmnd));
@@ -3591,7 +3591,7 @@
 
 int
 NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
-    struct Scsi_Host *host = cmd->host;
+    struct Scsi_Host *host = cmd->device->host;
     struct NCR53c7x0_hostdata *hostdata = 
 	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     unsigned long flags;
@@ -3604,9 +3604,9 @@
 
 #ifdef VALID_IDS
     /* Ignore commands on invalid IDs */
-    if (!hostdata->valid_ids[cmd->target]) {
+    if (!hostdata->valid_ids[cmd->device->id]) {
         printk("scsi%d : ignoring target %d lun %d\n", host->host_no,
-            cmd->target, cmd->lun);
+            cmd->device->id, cmd->device->lun);
         cmd->result = (DID_BAD_TARGET << 16);
         done(cmd);
         return 0;
@@ -3616,16 +3616,16 @@
     local_irq_save(flags);
     if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY)) 
 	|| ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
-	    !(hostdata->debug_lun_limit[cmd->target] & (1 << cmd->lun))) 
+	    !(hostdata->debug_lun_limit[cmd->device->id] & (1 << cmd->device->lun)))
 #ifdef LINUX_1_2
-	|| cmd->target > 7
+	|| cmd->device->id > 7
 #else
-	|| cmd->target > host->max_id
+	|| cmd->device->id > host->max_id
 #endif
-	|| cmd->target == host->this_id
+	|| cmd->device->id == host->this_id
 	|| hostdata->state == STATE_DISABLED) {
 	printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
-	    cmd->target, cmd->lun);
+	    cmd->device->id, cmd->device->lun);
 	cmd->result = (DID_BAD_TARGET << 16);
 	done(cmd);
 	local_irq_restore(flags);
@@ -3738,7 +3738,7 @@
 	--i, ncrcurrent += 2 /* JUMP instructions are two words */);
 
     if (i > 0) {
-	++hostdata->busy[tmp->target][tmp->lun];
+	++hostdata->busy[tmp->device->id][tmp->device->lun];
 	cmd->next = hostdata->running_list;
 	hostdata->running_list = cmd;
 
@@ -3799,7 +3799,7 @@
     /* FIXME : in the future, this needs to accommodate SCSI-II tagged
        queuing, and we may be able to play with fairness here a bit.
      */
-    return hostdata->busy[cmd->target][cmd->lun];
+    return hostdata->busy[cmd->device->id][cmd->device->lun];
 }
 
 /*
@@ -3873,7 +3873,7 @@
 			    if (tmp->host_scribble) {
 				if (hostdata->options & OPTION_DEBUG_QUEUES) 
 				    printk ("scsi%d : moving command for target %d lun %d to start list\n",
-					host->host_no, tmp->target, tmp->lun);
+					host->host_no, tmp->device->id, tmp->device->lun);
 		
 
 			    	to_schedule_list (host, hostdata, 
@@ -3937,7 +3937,7 @@
 	    printk ("scsi%d : Selection Timeout\n", host->host_no);
     	    if (cmd) {
     	    	printk("scsi%d : target %d, lun %d, command ",
-    	    	    host->host_no, cmd->cmd->target, cmd->cmd->lun);
+		    host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
     	    	print_command (cmd->cmd->cmnd);
 		printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
 		    NCR53c7x0_read32(DSP_REG),
@@ -3975,7 +3975,7 @@
 	fatal = 1;
 	if (cmd) {
 	    printk("scsi%d : target %d lun %d unexpected disconnect\n",
-		host->host_no, cmd->cmd->target, cmd->cmd->lun);
+		host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
 	    print_lots (host);
 	    abnormal_finished(cmd, DID_ERROR << 16);
 	} else 
@@ -3991,7 +3991,7 @@
 	fatal = 1;
 	if (cmd && cmd->cmd) {
 	    printk("scsi%d : target %d lun %d parity error.\n",
-		host->host_no, cmd->cmd->target, cmd->cmd->lun);
+		host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
 	    abnormal_finished (cmd, DID_PARITY << 16); 
 	} else
 	    printk("scsi%d : parity error\n", host->host_no);
@@ -4199,7 +4199,7 @@
 	if (cmd_prev_ptr)
 	    *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
 
-	--hostdata->busy[tmp->target][tmp->lun];
+	--hostdata->busy[tmp->device->id][tmp->device->lun];
 	cmd->next = hostdata->free;
 	hostdata->free = cmd;
 
@@ -4207,7 +4207,7 @@
 
 	if (hostdata->options & OPTION_DEBUG_INTR) {
 	    printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ", 
-		  host->host_no, tmp->pid, tmp->target, tmp->lun, tmp->result);
+		  host->host_no, tmp->pid, tmp->device->id, tmp->device->lun, tmp->result);
 	    print_command (tmp->cmnd);
 	}
 
@@ -4292,8 +4292,8 @@
 	if (hostdata->options & OPTION_DEBUG_INTR) {
 	    if (cmd) {
 		printk("scsi%d : interrupt for pid %lu, id %d, lun %d ", 
-		    host->host_no, cmd->cmd->pid, (int) cmd->cmd->target,
-		    (int) cmd->cmd->lun);
+		    host->host_no, cmd->cmd->pid, (int) cmd->cmd->device->id,
+		    (int) cmd->cmd->device->lun);
 		print_command (cmd->cmd->cmnd);
 	    } else {
 		printk("scsi%d : no active command\n", host->host_no);
@@ -4671,7 +4671,7 @@
 	    hostdata->dsp = dsp + 2 /* two _words_ */;
 	    hostdata->dsp_changed = 1;
 	    printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n", 
-		host->host_no, cmd->cmd->target);
+		host->host_no, cmd->cmd->device->id);
 	    cmd->flags &= ~CMD_FLAG_SDTR;
 	    action = ACTION_CONTINUE;
 	    break;
@@ -5136,7 +5136,7 @@
 int 
 NCR53c7xx_abort (Scsi_Cmnd *cmd) {
     NCR53c7x0_local_declare();
-    struct Scsi_Host *host = cmd->host;
+    struct Scsi_Host *host = cmd->device->host;
     struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *) 
 	host->hostdata[0] : NULL;
     unsigned long flags;
@@ -5242,7 +5242,7 @@
 	    return SCSI_ABORT_NOT_RUNNING;
 	} else {
 	    printk ("scsi%d : DANGER : command running, can not abort.\n",
-		cmd->host->host_no);
+		cmd->device->host->host_no);
 	    local_irq_restore(flags);
 	    return SCSI_ABORT_BUSY;
 	}
@@ -5273,7 +5273,7 @@
  * command was ever counted as BUSY, so if we end up here we can
  * decrement the busy count if and only if it is necessary.
  */
-        --hostdata->busy[cmd->target][cmd->lun];
+        --hostdata->busy[cmd->device->id][cmd->device->lun];
     }
     local_irq_restore(flags);
     cmd->scsi_done(cmd);
@@ -5318,7 +5318,7 @@
      * each command.  
      */
     Scsi_Cmnd *nuke_list = NULL;
-    struct Scsi_Host *host = cmd->host;
+    struct Scsi_Host *host = cmd->device->host;
     struct NCR53c7x0_hostdata *hostdata = 
     	(struct NCR53c7x0_hostdata *) host->hostdata[0];
 
@@ -5388,7 +5388,7 @@
 static int 
 insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) cmd->host->hostdata[0];
+	(struct NCR53c7x0_hostdata *) cmd->device->host->hostdata[0];
     struct NCR53c7x0_cmd *ncmd = 
 	(struct NCR53c7x0_cmd *) cmd->host_scribble;
     int offset = 0, buffers;
@@ -5418,7 +5418,7 @@
     	    	     --buffers, offset += segment->length, ++segment)
 #if 0
 		    printk("scsi%d: comparing 0x%p to 0x%p\n", 
-			cmd->host->host_no, saved, page_address(segment->page+segment->offset);
+			cmd->device->host->host_no, saved, page_address(segment->page+segment->offset);
 #else
 		    ;
 #endif
@@ -5456,7 +5456,7 @@
     int offset, i;
     char *where;
     u32 *ptr;
-    NCR53c7x0_local_setup (cmd->host);
+    NCR53c7x0_local_setup (cmd->device->host);
 
     if (check_address ((unsigned long) ncmd,sizeof (struct NCR53c7x0_cmd)) == 0)
     {
@@ -5484,15 +5484,15 @@
 
 	if (offset != -1) 
 	    printk ("scsi%d : %s data pointer at offset %d\n",
-		cmd->host->host_no, where, offset);
+		cmd->device->host->host_no, where, offset);
 	else {
 	    int size;
 	    printk ("scsi%d : can't determine %s data pointer offset\n",
-		cmd->host->host_no, where);
+		cmd->device->host->host_no, where);
 	    if (ncmd) {
-		size = print_insn (cmd->host, 
+		size = print_insn (cmd->device->host,
 		    bus_to_virt(ncmd->saved_data_pointer), "", 1);
-		print_insn (cmd->host, 
+		print_insn (cmd->device->host,
 		    bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
 		    "", 1);
 	    }
@@ -5549,7 +5549,7 @@
     /* XXX Maybe we should access cmd->host_scribble->result here. RGH */
     if (cmd) {
 	printk("               result = 0x%x, target = %d, lun = %d, cmd = ",
-	    cmd->result, cmd->target, cmd->lun);
+	    cmd->result, cmd->device->id, cmd->device->lun);
 	print_command(cmd->cmnd);
     } else
 	printk("\n");
@@ -5558,11 +5558,11 @@
     if (cmd) { 
 	printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
 	       "                   script : ",
-	    host->host_no, cmd->target,
-	    hostdata->sync[cmd->target].sxfer_sanity,
-	    hostdata->sync[cmd->target].scntl3_sanity);
-	for (i = 0; i < (sizeof(hostdata->sync[cmd->target].script) / 4); ++i)
-	    printk ("0x%x ", hostdata->sync[cmd->target].script[i]);
+	    host->host_no, cmd->device->id,
+	    hostdata->sync[cmd->device->id].sxfer_sanity,
+	    hostdata->sync[cmd->device->id].scntl3_sanity);
+	for (i = 0; i < (sizeof(hostdata->sync[cmd->device->id].script) / 4); ++i)
+	    printk ("0x%x ", hostdata->sync[cmd->device->id].script[i]);
 	printk ("\n");
     	print_progress (cmd);
     }
@@ -5604,7 +5604,7 @@
 		    -> dsa, "");
 	} else 
 	    printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
-		host->host_no, cmd->pid, cmd->target, cmd->lun);
+		host->host_no, cmd->pid, cmd->device->id, cmd->device->lun);
 	local_irq_restore(flags);
     }
 
diff -urN linux-2.5.65-bk1/drivers/scsi/NCR53C9x.c linux-2.5.65-bk2/drivers/scsi/NCR53C9x.c
--- linux-2.5.65-bk1/drivers/scsi/NCR53C9x.c	Mon Mar 17 13:43:47 2003
+++ linux-2.5.65-bk2/drivers/scsi/NCR53C9x.c	Mon Mar 31 12:39:50 2003
@@ -1099,7 +1099,7 @@
 		 * disconnect.
 		 */
 		ESPMISC(("esp: Selecting device for first time. target=%d "
-			 "lun=%d\n", target, SCptr->lun));
+			 "lun=%d\n", target, SCptr->device->lun));
 		if(!SDptr->borken && !esp_dev->disconnect)
 			esp_dev->disconnect = 1;
 
@@ -1173,7 +1173,7 @@
 		if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
 		   toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
 			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
-				 "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
+				 "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
 			esp_dev->disconnect = 0;
 			*cmdp++ = IDENTIFY(0, lun);
 		} else {
@@ -1255,8 +1255,8 @@
 		esp->dma_led_on(esp);
 
 	/* We use the scratch area. */
-	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));
-	ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));
+	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->lun));
+	ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->lun));
 
 	esp_get_dmabufs(esp, SCpnt);
 	esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
@@ -2235,7 +2235,7 @@
 			 * state.
 			 */
 			ESPMISC(("esp: Status <%d> for target %d lun %d\n",
-				 SCptr->SCp.Status, SCptr->target, SCptr->lun));
+				 SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun));
 
 			/* But don't do this when spinning up a disk at
 			 * boot time while we poll for completion as it
@@ -2246,14 +2246,14 @@
 			if(esp_should_clear_sync(SCptr) != 0)
 				esp_dev->sync = 0;
 		}
-		ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
+		ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
 		esp_done(esp, ((SCptr->SCp.Status & 0xff) |
 			       ((SCptr->SCp.Message & 0xff)<<8) |
 			       (DID_OK << 16)));
 	} else if(esp->prevmsgin == DISCONNECT) {
 		/* Normal disconnect. */
 		esp_cmd(esp, eregs, ESP_CMD_ESEL);
-		ESPDISC(("D<%02x,%02x>", SCptr->target, SCptr->lun));
+		ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
 		append_SC(&esp->disconnected_SC, SCptr);
 		esp->current_SC = NULL;
 		if(esp->issue_SC)
@@ -2811,7 +2811,7 @@
 			/* Else, there really isn't anyone there. */
 			ESPMISC(("esp: selection failure, maybe nobody there?\n"));
 			ESPMISC(("esp: target %d lun %d\n",
-				 SCptr->target, SCptr->lun));
+				 SCptr->device->id, SCptr->device->lun));
 			esp_done(esp, (DID_BAD_TARGET << 16));
 		}
 		return do_intr_end;
@@ -3084,7 +3084,7 @@
 			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
 				esp_dev->sync_max_offset,
 				esp_dev->sync_min_period,
-				esp->config3[SCptr->target]));
+				esp->config3[SCptr->device->id]));
 
 			esp->snip = 0;
 		} else if(esp_dev->sync_max_offset) {
diff -urN linux-2.5.65-bk1/drivers/scsi/a2091.c linux-2.5.65-bk2/drivers/scsi/a2091.c
--- linux-2.5.65-bk1/drivers/scsi/a2091.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/drivers/scsi/a2091.c	Mon Mar 31 12:39:50 2003
@@ -52,7 +52,7 @@
 {
     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
     unsigned long addr = virt_to_bus(cmd->SCp.ptr);
-    struct Scsi_Host *instance = cmd->host;
+    struct Scsi_Host *instance = cmd->device->host;
 
     /* don't allow DMA if the physical address is bad */
     if (addr & A2091_XFER_MASK ||
@@ -102,12 +102,12 @@
 	cntr |= CNTR_DDIR;
 
     /* remember direction */
-    HDATA(cmd->host)->dma_dir = dir_in;
+    HDATA(cmd->device->host)->dma_dir = dir_in;
 
-    DMA(cmd->host)->CNTR = cntr;
+    DMA(cmd->device->host)->CNTR = cntr;
 
     /* setup DMA *physical* address */
-    DMA(cmd->host)->ACR = addr;
+    DMA(cmd->device->host)->ACR = addr;
 
     if (dir_in){
 	/* invalidate any cache */
@@ -117,7 +117,7 @@
 	cache_push (addr, cmd->SCp.this_residual);
       }
     /* start DMA */
-    DMA(cmd->host)->ST_DMA = 1;
+    DMA(cmd->device->host)->ST_DMA = 1;
 
     /* return success */
     return 0;
diff -urN linux-2.5.65-bk1/drivers/scsi/a3000.c linux-2.5.65-bk2/drivers/scsi/a3000.c
--- linux-2.5.65-bk1/drivers/scsi/a3000.c	Mon Mar 17 13:44:22 2003
+++ linux-2.5.65-bk2/drivers/scsi/a3000.c	Mon Mar 31 12:39:50 2003
@@ -225,7 +225,7 @@
 
 #include "scsi_module.c"
 
-int __exit a3000_release(struct Scsi_Host *instance)
+int a3000_release(struct Scsi_Host *instance)
 {
     wd33c93_release();
     DMA(instance)->CNTR = 0;
diff -urN linux-2.5.65-bk1/drivers/scsi/amiga7xx.c linux-2.5.65-bk2/drivers/scsi/amiga7xx.c
--- linux-2.5.65-bk1/drivers/scsi/amiga7xx.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/drivers/scsi/amiga7xx.c	Mon Mar 31 12:39:50 2003
@@ -86,7 +86,7 @@
 #ifdef CONFIG_WARPENGINE_SCSI
     	    case ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx:
 		if (request_mem_region(address+0x40000, 0x1000, "ncr53c710")) {
-		    address = (unsigned long)ioremap(address, size);
+		    address = (unsigned long)z_ioremap(address, size);
 		    options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 |
 			      OPTION_INTFLY | OPTION_SYNCHRONOUS |
 			      OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT;
@@ -102,7 +102,7 @@
 	    case ZORRO_PROD_CBM_A4091_1:
 	    case ZORRO_PROD_CBM_A4091_2:
 		if (request_mem_region(address+0x800000, 0x1000, "ncr53c710")) {
-		    address = (unsigned long)ioremap(address, size);
+		    address = (unsigned long)z_ioremap(address, size);
 		    options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 |
 			      OPTION_INTFLY | OPTION_SYNCHRONOUS |
 			      OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT;
diff -urN linux-2.5.65-bk1/drivers/scsi/atari_NCR5380.c linux-2.5.65-bk2/drivers/scsi/atari_NCR5380.c
--- linux-2.5.65-bk1/drivers/scsi/atari_NCR5380.c	Mon Mar 17 13:44:08 2003
+++ linux-2.5.65-bk2/drivers/scsi/atari_NCR5380.c	Mon Mar 31 12:39:50 2003
@@ -266,7 +266,7 @@
 #define	NEXTADDR(cmd)	((Scsi_Cmnd **)&((cmd)->host_scribble))
 
 #define	HOSTNO		instance->host_no
-#define	H_NO(cmd)	(cmd)->host->host_no
+#define	H_NO(cmd)	(cmd)->device->host->host_no
 
 #ifdef SUPPORT_TAGS
 
@@ -350,17 +350,17 @@
 
 static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
 
-    if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+    if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
 	return( 1 );
     if (!should_be_tagged ||
 	!setup_use_tagged_queuing || !cmd->device->tagged_supported)
 	return( 0 );
-    if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
-	TagAlloc[cmd->target][cmd->lun].queue_size ) {
+    if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+	TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
 	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
-		    H_NO(cmd), cmd->target, cmd->lun );
+		    H_NO(cmd), cmd->device->id, cmd->device->lun );
 	return( 1 );
     }
     return( 0 );
@@ -374,7 +374,7 @@
 
 static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
 
     /* If we or the target don't support tagged queuing, allocate the LUN for
      * an untagged command.
@@ -382,19 +382,19 @@
     if (!should_be_tagged ||
 	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
 	cmd->tag = TAG_NONE;
-	hostdata->busy[cmd->target] |= (1 << cmd->lun);
+	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
 	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
-		    "command\n", H_NO(cmd), cmd->target, cmd->lun );
+		    "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
     }
     else {
-	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
 
 	cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS );
 	set_bit( cmd->tag, ta->allocated );
 	ta->nr_allocated++;
 	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
 		    "(now %d tags in use)\n",
-		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
 		    ta->nr_allocated );
     }
 }
@@ -406,23 +406,23 @@
 
 static void cmd_free_tag( Scsi_Cmnd *cmd )
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
 
     if (cmd->tag == TAG_NONE) {
-	hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+	hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
-		    H_NO(cmd), cmd->target, cmd->lun );
+		    H_NO(cmd), cmd->device->id, cmd->device->lun );
     }
     else if (cmd->tag >= MAX_TAGS) {
 	printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
 		H_NO(cmd), cmd->tag );
     }
     else {
-	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
 	clear_bit( cmd->tag, ta->allocated );
 	ta->nr_allocated--;
 	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
-		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
     }
 }
 
@@ -811,7 +811,7 @@
     int i, s;
     unsigned char *command;
     SPRINTF("scsi%d: destination target %d, lun %d\n",
-	    H_NO(cmd), cmd->target, cmd->lun);
+	    H_NO(cmd), cmd->device->id, cmd->device->lun);
     SPRINTF("        command = ");
     command = cmd->cmnd;
     SPRINTF("%2d (0x%02x)", command[0], command[0]);
@@ -834,7 +834,7 @@
  * 
  */
 
-static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init (struct Scsi_Host *instance, int flags)
 {
     int i;
     SETUP_HOSTDATA(instance);
@@ -878,6 +878,8 @@
     NCR5380_write(MODE_REG, MR_BASE);
     NCR5380_write(TARGET_COMMAND_REG, 0);
     NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    return 0;
 }
 
 /* 
@@ -898,13 +900,10 @@
  *
  */
 
-/* Only make static if a wrapper function is used */
-#ifndef NCR5380_queue_command
 static
-#endif
 int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
     Scsi_Cmnd *tmp;
     int oldto;
     unsigned long flags;
@@ -938,15 +937,15 @@
 	    case WRITE:
 	    case WRITE_6:
 	    case WRITE_10:
-		hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
-		hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+		hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
 		hostdata->pendingw++;
 		break;
 	    case READ:
 	    case READ_6:
 	    case READ_10:
-		hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
-		hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+		hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
 		hostdata->pendingr++;
 		break;
 	}
@@ -1014,7 +1013,7 @@
     if (in_interrupt() || ((flags >> 8) & 7) >= 6)
 	queue_main();
     else
-	NCR5380_main();
+	NCR5380_main(NULL);
     return 0;
 }
 
@@ -1030,7 +1029,7 @@
  *  reenable them.  This prevents reentrancy and kernel stack overflow.
  */ 	
     
-static void NCR5380_main (void)
+static void NCR5380_main (void *bl)
 {
     Scsi_Cmnd *tmp, *prev;
     struct Scsi_Host *instance = first_instance;
@@ -1087,8 +1086,8 @@
 #if (NDEBUG & NDEBUG_LISTS)
 		if (prev != tmp)
 		    printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n",
-			   tmp, tmp->target, hostdata->busy[tmp->target],
-			   tmp->lun);
+			   tmp, tmp->device->id, hostdata->busy[tmp->device->id],
+			   tmp->device->lun);
 #endif
 		/*  When we find one, remove it from the issue queue. */
 		/* ++guenther: possible race with Falcon locking */
@@ -1096,7 +1095,7 @@
 #ifdef SUPPORT_TAGS
 		    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
 #else
-		    !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+		    !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
 #endif
 		    ) {
 		    /* ++guenther: just to be sure, this must be atomic */
@@ -1122,7 +1121,7 @@
 		     */
 		    MAIN_PRINTK("scsi%d: main(): command for target %d "
 				"lun %d removed from issue_queue\n",
-				HOSTNO, tmp->target, tmp->lun);
+				HOSTNO, tmp->device->id, tmp->device->lun);
 		    /* 
 		     * REQUEST SENSE commands are issued without tagged
 		     * queueing, even on SCSI-II devices because the 
@@ -1356,15 +1355,15 @@
 	    case WRITE:
 	    case WRITE_6:
 	    case WRITE_10:
-		hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
-		/*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
 		hostdata->pendingw--;
 		break;
 	    case READ:
 	    case READ_6:
 	    case READ_10:
-		hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
-		/*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
 		hostdata->pendingr--;
 		break;
 	}
@@ -1525,7 +1524,7 @@
      * the host and target ID's on the SCSI bus.
      */
 
-    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
 
     /* 
      * Raise ATN while SEL is true before BSY goes false from arbitration,
@@ -1578,7 +1577,7 @@
 
     udelay(1);
 
-    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
 
     /* 
      * The SCSI specification calls for a 250 ms timeout for the actual 
@@ -1629,7 +1628,7 @@
 
     if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	if (hostdata->targets_present & (1 << cmd->target)) {
+	if (hostdata->targets_present & (1 << cmd->device->id)) {
 	    printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
 	    if (hostdata->restart_select)
 		printk(KERN_NOTICE "\trestart select\n");
@@ -1651,7 +1650,7 @@
 	return 0;
     } 
 
-    hostdata->targets_present |= (1 << cmd->target);
+    hostdata->targets_present |= (1 << cmd->device->id);
 
     /*
      * Since we followed the SCSI spec, and raised ATN while SEL 
@@ -1672,8 +1671,8 @@
     while (!(NCR5380_read(STATUS_REG) & SR_REQ));
 
     SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
-	       HOSTNO, cmd->target);
-    tmp[0] = IDENTIFY(1, cmd->lun);
+	       HOSTNO, cmd->device->id);
+    tmp[0] = IDENTIFY(1, cmd->device->lun);
 
 #ifdef SUPPORT_TAGS
     if (cmd->tag != TAG_NONE) {
@@ -1695,7 +1694,7 @@
     /* XXX need to handle errors here */
     hostdata->connected = cmd;
 #ifndef SUPPORT_TAGS
-    hostdata->busy[cmd->target] |= (1 << cmd->lun);
+    hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
 #endif    
 
     initialize_SCp(cmd);
@@ -2085,7 +2084,7 @@
 			 * polled-IO. */ 
 			printk(KERN_NOTICE "scsi%d: switching target %d "
 			       "lun %d to slow handshake\n", HOSTNO,
-			       cmd->target, cmd->lun);
+			       cmd->device->id, cmd->device->lun);
 			cmd->device->borken = 1;
 			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
 			    ICR_ASSERT_ATN);
@@ -2137,7 +2136,7 @@
 		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 		    
 		    LNK_PRINTK("scsi%d: target %d lun %d linked command "
-			       "complete.\n", HOSTNO, cmd->target, cmd->lun);
+			       "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
 
 		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -2150,7 +2149,7 @@
 		    if (!cmd->next_link) {
 			 printk(KERN_NOTICE "scsi%d: target %d lun %d "
 				"linked command complete, no next_link\n",
-				HOSTNO, cmd->target, cmd->lun);
+				HOSTNO, cmd->device->id, cmd->device->lun);
 			    sink = 1;
 			    do_abort (instance);
 			    return;
@@ -2163,7 +2162,7 @@
 		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
 		    LNK_PRINTK("scsi%d: target %d lun %d linked request "
 			       "done, calling scsi_done().\n",
-			       HOSTNO, cmd->target, cmd->lun);
+			       HOSTNO, cmd->device->id, cmd->device->lun);
 #ifdef NCR5380_STATS
 		    collect_stats(hostdata, cmd);
 #endif
@@ -2179,7 +2178,7 @@
 		    falcon_dont_release++;
 		    hostdata->connected = NULL;
 		    QU_PRINTK("scsi%d: command for target %d, lun %d "
-			      "completed\n", HOSTNO, cmd->target, cmd->lun);
+			      "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
 #ifdef SUPPORT_TAGS
 		    cmd_free_tag( cmd );
 		    if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
@@ -2191,16 +2190,16 @@
 			 */
 			/* ++Andreas: the mid level code knows about
 			   QUEUE_FULL now. */
-			TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+			TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
 			TAG_PRINTK("scsi%d: target %d lun %d returned "
 				   "QUEUE_FULL after %d commands\n",
-				   HOSTNO, cmd->target, cmd->lun,
+				   HOSTNO, cmd->device->id, cmd->device->lun,
 				   ta->nr_allocated);
 			if (ta->queue_size > ta->nr_allocated)
 			    ta->nr_allocated = ta->queue_size;
 		    }
 #else
-		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
 		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -2296,12 +2295,12 @@
 			 * the command is treated as untagged further on.
 			 */
 			cmd->device->tagged_supported = 0;
-			hostdata->busy[cmd->target] |= (1 << cmd->lun);
+			hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
 			cmd->tag = TAG_NONE;
 			TAG_PRINTK("scsi%d: target %d lun %d rejected "
 				   "QUEUE_TAG message; tagged queuing "
 				   "disabled\n",
-				   HOSTNO, cmd->target, cmd->lun);
+				   HOSTNO, cmd->device->id, cmd->device->lun);
 			break;
 		    }
 		    break;
@@ -2318,7 +2317,7 @@
 		    QU_PRINTK("scsi%d: command for target %d lun %d was "
 			      "moved from connected to the "
 			      "disconnected_queue\n", HOSTNO, 
-			      cmd->target, cmd->lun);
+			      cmd->device->id, cmd->device->lun);
 		    /* 
 		     * Restore phase bits to 0 so an interrupted selection, 
 		     * arbitration can resume.
@@ -2417,13 +2416,13 @@
 		    } else if (tmp != EXTENDED_MESSAGE)
 			printk(KERN_DEBUG "scsi%d: rejecting unknown "
 			       "message %02x from target %d, lun %d\n",
-			       HOSTNO, tmp, cmd->target, cmd->lun);
+			       HOSTNO, tmp, cmd->device->id, cmd->device->lun);
 		    else
 			printk(KERN_DEBUG "scsi%d: rejecting unknown "
 			       "extended message "
 			       "code %02x, length %d from target %d, lun %d\n",
 			       HOSTNO, extended_msg[1], extended_msg[0],
-			       cmd->target, cmd->lun);
+			       cmd->device->id, cmd->device->lun);
    
 
 		    msgout = MESSAGE_REJECT;
@@ -2441,7 +2440,7 @@
 #ifdef SUPPORT_TAGS
 		    cmd_free_tag( cmd );
 #else
-		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
 		    hostdata->connected = NULL;
 		    cmd->result = DID_ERROR << 16;
@@ -2577,7 +2576,7 @@
 
     for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
 	 tmp; prev = tmp, tmp = NEXT(tmp) ) {
-	if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+	if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
 #ifdef SUPPORT_TAGS
 	    && (tag == tmp->tag) 
 #endif
@@ -2620,7 +2619,7 @@
 
     hostdata->connected = tmp;
     RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
-	       HOSTNO, tmp->target, tmp->lun, tmp->tag);
+	       HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
     falcon_dont_release--;
 }
 
@@ -2642,12 +2641,10 @@
  * 	 called where the loop started in NCR5380_main().
  */
 
-#ifndef NCR5380_abort
 static
-#endif
 int NCR5380_abort (Scsi_Cmnd *cmd)
 {
-    struct Scsi_Host *instance = cmd->host;
+    struct Scsi_Host *instance = cmd->device->host;
     SETUP_HOSTDATA(instance);
     Scsi_Cmnd *tmp, **prev;
     unsigned long flags;
@@ -2701,7 +2698,7 @@
 #ifdef SUPPORT_TAGS
 	  cmd_free_tag( cmd );
 #else
-	  hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+	  hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
 	  local_irq_restore(flags);
 	  cmd->scsi_done(cmd);
@@ -2808,7 +2805,7 @@
 #ifdef SUPPORT_TAGS
 		    cmd_free_tag( tmp );
 #else
-		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
 		    local_irq_restore(flags);
 		    tmp->scsi_done(tmp);
@@ -2842,7 +2839,7 @@
 
 
 /* 
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
  * 
  * Purpose : reset the SCSI bus.
  *
@@ -2850,9 +2847,9 @@
  *
  */ 
 
-static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
     int           i;
     unsigned long flags;
 #if 1
@@ -2863,7 +2860,7 @@
 	printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
 	       H_NO(cmd) );
 
-    NCR5380_print_status (cmd->host);
+    NCR5380_print_status (cmd->device->host);
 
     /* get in phase */
     NCR5380_write( TARGET_COMMAND_REG,
diff -urN linux-2.5.65-bk1/drivers/scsi/atari_scsi.c linux-2.5.65-bk2/drivers/scsi/atari_scsi.c
--- linux-2.5.65-bk1/drivers/scsi/atari_scsi.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/drivers/scsi/atari_scsi.c	Mon Mar 31 12:39:50 2003
@@ -819,11 +819,11 @@
 #endif
 }
 
-int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
 {
 	int		rv;
 	struct NCR5380_hostdata *hostdata =
-		(struct NCR5380_hostdata *)cmd->host->hostdata;
+		(struct NCR5380_hostdata *)cmd->device->host->hostdata;
 
 	/* For doing the reset, SCSI interrupts must be disabled first,
 	 * since the 5380 raises its IRQ line while _RST is active and we
@@ -845,7 +845,7 @@
 #endif /* REAL_DMA */
 	}
 
-	rv = NCR5380_reset(cmd, reset_flags);
+	rv = NCR5380_bus_reset(cmd);
 
 	/* Re-enable ints */
 	if (IS_A_TT()) {
@@ -1146,8 +1146,8 @@
 	.release		= atari_scsi_release,
 	.info			= atari_scsi_info,
 	.queuecommand		= atari_scsi_queue_command,
-	.abort			= atari_scsi_abort,
-	.reset			= atari_scsi_reset,
+	.eh_abort_handler	= atari_scsi_abort,
+	.eh_bus_reset_handler	= atari_scsi_bus_reset,
 	.can_queue		= 0, /* initialized at run-time */
 	.this_id		= 0, /* initialized at run-time */
 	.sg_tablesize		= 0, /* initialized at run-time */
diff -urN linux-2.5.65-bk1/drivers/scsi/atari_scsi.h linux-2.5.65-bk2/drivers/scsi/atari_scsi.h
--- linux-2.5.65-bk1/drivers/scsi/atari_scsi.h	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/drivers/scsi/atari_scsi.h	Mon Mar 31 12:39:50 2003
@@ -18,10 +18,8 @@
 /* (I_HAVE_OVERRUNS stuff removed) */
 
 #ifndef ASM
-int atari_scsi_abort (Scsi_Cmnd *);
 int atari_scsi_detect (Scsi_Host_Template *);
 const char *atari_scsi_info (struct Scsi_Host *);
-int atari_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
 int atari_scsi_proc_info (char *, char **, off_t, int, int, int);
 #ifdef MODULE
diff -urN linux-2.5.65-bk1/drivers/scsi/blz1230.c linux-2.5.65-bk2/drivers/scsi/blz1230.c
--- linux-2.5.65-bk1/drivers/scsi/blz1230.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/drivers/scsi/blz1230.c	Mon Mar 31 12:39:50 2003
@@ -167,8 +167,8 @@
 		esp->eregs = eregs;
 
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		esp->slot = board+REAL_BLZ1230_ESP_ADDR;
diff -urN linux-2.5.65-bk1/drivers/scsi/blz2060.c linux-2.5.65-bk2/drivers/scsi/blz2060.c
--- linux-2.5.65-bk1/drivers/scsi/blz2060.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/scsi/blz2060.c	Mon Mar 31 12:39:50 2003
@@ -142,8 +142,8 @@
 		esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
 		
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff -urN linux-2.5.65-bk1/drivers/scsi/cyberstorm.c linux-2.5.65-bk2/drivers/scsi/cyberstorm.c
--- linux-2.5.65-bk1/drivers/scsi/cyberstorm.c	Mon Mar 17 13:44:38 2003
+++ linux-2.5.65-bk2/drivers/scsi/cyberstorm.c	Mon Mar 31 12:39:50 2003
@@ -168,8 +168,8 @@
 		esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
 		
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff -urN linux-2.5.65-bk1/drivers/scsi/cyberstormII.c linux-2.5.65-bk2/drivers/scsi/cyberstormII.c
--- linux-2.5.65-bk1/drivers/scsi/cyberstormII.c	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/drivers/scsi/cyberstormII.c	Mon Mar 31 12:39:50 2003
@@ -149,8 +149,8 @@
 		esp->eregs = eregs;
 		
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff -urN linux-2.5.65-bk1/drivers/scsi/fastlane.c linux-2.5.65-bk2/drivers/scsi/fastlane.c
--- linux-2.5.65-bk1/drivers/scsi/fastlane.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/drivers/scsi/fastlane.c	Mon Mar 31 12:39:50 2003
@@ -191,8 +191,8 @@
 		esp->edev = (void *) address;
 		
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		esp->slot = board+FASTLANE_ESP_ADDR;
diff -urN linux-2.5.65-bk1/drivers/scsi/gvp11.c linux-2.5.65-bk2/drivers/scsi/gvp11.c
--- linux-2.5.65-bk1/drivers/scsi/gvp11.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/drivers/scsi/gvp11.c	Mon Mar 31 12:39:50 2003
@@ -62,61 +62,62 @@
     static int scsi_alloc_out_of_range = 0;
 
     /* use bounce buffer if the physical address is bad */
-    if (addr & HDATA(cmd->host)->dma_xfer_mask ||
+    if (addr & HDATA(cmd->device->host)->dma_xfer_mask ||
 	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
     {
-	HDATA(cmd->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
+	HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
 	    & ~0x1ff;
 
  	if( !scsi_alloc_out_of_range ) {
-	    HDATA(cmd->host)->dma_bounce_buffer =
-		kmalloc (HDATA(cmd->host)->dma_bounce_len, GFP_KERNEL);
-	    HDATA(cmd->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
+	    HDATA(cmd->device->host)->dma_bounce_buffer =
+		kmalloc (HDATA(cmd->device->host)->dma_bounce_len, GFP_KERNEL);
+	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
 	}
 
-	if ( scsi_alloc_out_of_range || !HDATA(cmd->host)->dma_bounce_buffer) {
-	    HDATA(cmd->host)->dma_bounce_buffer =
-		amiga_chip_alloc(HDATA(cmd->host)->dma_bounce_len,
+	if (scsi_alloc_out_of_range ||
+	    !HDATA(cmd->device->host)->dma_bounce_buffer) {
+	    HDATA(cmd->device->host)->dma_bounce_buffer =
+		amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
 				       "GVP II SCSI Bounce Buffer");
 
-	    if(!HDATA(cmd->host)->dma_bounce_buffer)
+	    if(!HDATA(cmd->device->host)->dma_bounce_buffer)
 	    {
-		HDATA(cmd->host)->dma_bounce_len = 0;
+		HDATA(cmd->device->host)->dma_bounce_len = 0;
 		return 1;
 	    }
 
-	    HDATA(cmd->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
+	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
 	}
 
 	/* check if the address of the bounce buffer is OK */
-	addr = virt_to_bus(HDATA(cmd->host)->dma_bounce_buffer);
+	addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
 
-	if (addr & HDATA(cmd->host)->dma_xfer_mask) {
+	if (addr & HDATA(cmd->device->host)->dma_xfer_mask) {
 	    /* fall back to Chip RAM if address out of range */
-	    if( HDATA(cmd->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
-		kfree (HDATA(cmd->host)->dma_bounce_buffer);
+	    if( HDATA(cmd->device->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
+		kfree (HDATA(cmd->device->host)->dma_bounce_buffer);
 		scsi_alloc_out_of_range = 1;
 	    } else {
-		amiga_chip_free (HDATA(cmd->host)->dma_bounce_buffer);
+		amiga_chip_free (HDATA(cmd->device->host)->dma_bounce_buffer);
             }
 		
-	    HDATA(cmd->host)->dma_bounce_buffer =
-		amiga_chip_alloc(HDATA(cmd->host)->dma_bounce_len,
+	    HDATA(cmd->device->host)->dma_bounce_buffer =
+		amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
 				       "GVP II SCSI Bounce Buffer");
 
-	    if(!HDATA(cmd->host)->dma_bounce_buffer)
+	    if(!HDATA(cmd->device->host)->dma_bounce_buffer)
 	    {
-		HDATA(cmd->host)->dma_bounce_len = 0;
+		HDATA(cmd->device->host)->dma_bounce_len = 0;
 		return 1;
 	    }
 
-	    addr = virt_to_bus(HDATA(cmd->host)->dma_bounce_buffer);
-	    HDATA(cmd->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
+	    addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
+	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
 	}
 	    
 	if (!dir_in) {
 	    /* copy to bounce buffer for a write */
-	    memcpy (HDATA(cmd->host)->dma_bounce_buffer,
+	    memcpy (HDATA(cmd->device->host)->dma_bounce_buffer,
 		    cmd->SCp.ptr, cmd->SCp.this_residual);
 	}
     }
@@ -125,11 +126,11 @@
     if (!dir_in)
 	cntr |= GVP11_DMAC_DIR_WRITE;
 
-    HDATA(cmd->host)->dma_dir = dir_in;
-    DMA(cmd->host)->CNTR = cntr;
+    HDATA(cmd->device->host)->dma_dir = dir_in;
+    DMA(cmd->device->host)->CNTR = cntr;
 
     /* setup DMA *physical* address */
-    DMA(cmd->host)->ACR = addr;
+    DMA(cmd->device->host)->ACR = addr;
 
     if (dir_in)
 	/* invalidate any cache */
@@ -138,11 +139,11 @@
 	/* push any dirty cache */
 	cache_push (addr, cmd->SCp.this_residual);
 
-    if ((bank_mask = (~HDATA(cmd->host)->dma_xfer_mask >> 18) & 0x01c0))
-	    DMA(cmd->host)->BANK = bank_mask & (addr >> 18);
+    if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0))
+	    DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
 
     /* start DMA */
-    DMA(cmd->host)->ST_DMA = 1;
+    DMA(cmd->device->host)->ST_DMA = 1;
 
     /* return success */
     return 0;
diff -urN linux-2.5.65-bk1/drivers/scsi/mac_NCR5380.c linux-2.5.65-bk2/drivers/scsi/mac_NCR5380.c
--- linux-2.5.65-bk1/drivers/scsi/mac_NCR5380.c	Mon Mar 17 13:44:39 2003
+++ linux-2.5.65-bk2/drivers/scsi/mac_NCR5380.c	Mon Mar 31 12:39:50 2003
@@ -850,7 +850,7 @@
 
 
 /* 
- * Function : void NCR5380_init (struct Scsi_Host *instance)
+ * Function : void NCR5380_init (struct Scsi_Host *instance, int flags)
  *
  * Purpose : initializes *instance and corresponding 5380 chip.
  *
@@ -861,7 +861,7 @@
  * 
  */
 
-static void NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init (struct Scsi_Host *instance, int flags)
 {
     int i;
     SETUP_HOSTDATA(instance);
@@ -905,6 +905,8 @@
     NCR5380_write(MODE_REG, MR_BASE);
     NCR5380_write(TARGET_COMMAND_REG, 0);
     NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    return 0;
 }
 
 /* 
@@ -925,17 +927,13 @@
  *
  */
 
-/* Only make static if a wrapper function is used */
-#ifndef NCR5380_queue_command
 static
-#endif
 int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
     SETUP_HOSTDATA(cmd->host);
     Scsi_Cmnd *tmp;
     int oldto;
     unsigned long flags;
-    extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
     switch (cmd->cmnd[0]) {
@@ -1025,12 +1023,12 @@
     if (in_interrupt() > 0 || ((flags >> 8) & 7) >= 6)
 	queue_main();
     else
-	NCR5380_main();
+	NCR5380_main(NULL);
     return 0;
 }
 
 /*
- * Function : NCR5380_main (void) 
+ * Function : NCR5380_main (void *bl)
  *
  * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
  *	be done on the NCR5380 host adapters in a system.  Both 
@@ -1041,7 +1039,7 @@
  *  reenable them.  This prevents reentrancy and kernel stack overflow.
  */ 	
     
-static void NCR5380_main (void)
+static void NCR5380_main (void *bl)
 {
     Scsi_Cmnd *tmp, *prev;
     struct Scsi_Host *instance = first_instance;
@@ -2790,9 +2788,6 @@
  * 	 called where the loop started in NCR5380_main().
  */
 
-#ifndef NCR5380_abort
-static
-#endif
 int NCR5380_abort (Scsi_Cmnd *cmd)
 {
     struct Scsi_Host *instance = cmd->host;
@@ -2982,7 +2977,7 @@
 
 
 /* 
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
  * 
  * Purpose : reset the SCSI bus.
  *
@@ -2990,7 +2985,7 @@
  *
  */ 
 
-static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
 {
     SETUP_HOSTDATA(cmd->host);
     int           i;
diff -urN linux-2.5.65-bk1/drivers/scsi/sun3_NCR5380.c linux-2.5.65-bk2/drivers/scsi/sun3_NCR5380.c
--- linux-2.5.65-bk1/drivers/scsi/sun3_NCR5380.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/drivers/scsi/sun3_NCR5380.c	Mon Mar 31 12:39:50 2003
@@ -268,7 +268,7 @@
 #define	NEXTADDR(cmd)	((Scsi_Cmnd **)&((cmd)->host_scribble))
 
 #define	HOSTNO		instance->host_no
-#define	H_NO(cmd)	(cmd)->host->host_no
+#define	H_NO(cmd)	(cmd)->device->host->host_no
 
 #define SGADDR(buffer) (void *)(((unsigned long)page_address((buffer)->page)) + \
 			(buffer)->offset)
@@ -360,17 +360,17 @@
 
 static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
 
-    if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+    if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
 	return( 1 );
     if (!should_be_tagged ||
 	!setup_use_tagged_queuing || !cmd->device->tagged_supported)
 	return( 0 );
-    if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
-	TagAlloc[cmd->target][cmd->lun].queue_size ) {
+    if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+	TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
 	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
-		    H_NO(cmd), cmd->target, cmd->lun );
+		    H_NO(cmd), cmd->device->id, cmd->device->lun );
 	return( 1 );
     }
     return( 0 );
@@ -384,7 +384,7 @@
 
 static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
 
     /* If we or the target don't support tagged queuing, allocate the LUN for
      * an untagged command.
@@ -392,19 +392,19 @@
     if (!should_be_tagged ||
 	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
 	cmd->tag = TAG_NONE;
-	hostdata->busy[cmd->target] |= (1 << cmd->lun);
+	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
 	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
-		    "command\n", H_NO(cmd), cmd->target, cmd->lun );
+		    "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
     }
     else {
-	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
 
 	cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
 	set_bit( cmd->tag, &ta->allocated );
 	ta->nr_allocated++;
 	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
 		    "(now %d tags in use)\n",
-		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
 		    ta->nr_allocated );
     }
 }
@@ -416,23 +416,23 @@
 
 static void cmd_free_tag( Scsi_Cmnd *cmd )
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
 
     if (cmd->tag == TAG_NONE) {
-	hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+	hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
-		    H_NO(cmd), cmd->target, cmd->lun );
+		    H_NO(cmd), cmd->device->id, cmd->device->lun );
     }
     else if (cmd->tag >= MAX_TAGS) {
 	printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
 		H_NO(cmd), cmd->tag );
     }
     else {
-	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
 	clear_bit( cmd->tag, &ta->allocated );
 	ta->nr_allocated--;
 	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
-		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
     }
 }
 
@@ -616,11 +616,11 @@
 
     status = NCR5380_read(STATUS_REG);
     if (!(status & SR_REQ)) 
-	printk("scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+	printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
     else {
 	for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
 	    (phases[i].value != (status & PHASE_MASK)); ++i); 
-	printk("scsi%d: phase %s\n", HOSTNO, phases[i].name);
+	printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
     }
 }
 
@@ -819,7 +819,7 @@
     int i, s;
     unsigned char *command;
     SPRINTF("scsi%d: destination target %d, lun %d\n",
-	    H_NO(cmd), cmd->target, cmd->lun);
+	    H_NO(cmd), cmd->device->id, cmd->device->lun);
     SPRINTF("        command = ");
     command = cmd->cmnd;
     SPRINTF("%2d (0x%02x)", command[0], command[0]);
@@ -842,7 +842,7 @@
  * 
  */
 
-static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init (struct Scsi_Host *instance, int flags)
 {
     int i;
     SETUP_HOSTDATA(instance);
@@ -886,6 +886,8 @@
     NCR5380_write(MODE_REG, MR_BASE);
     NCR5380_write(TARGET_COMMAND_REG, 0);
     NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    return 0;
 }
 
 /* 
@@ -909,10 +911,9 @@
 /* Only make static if a wrapper function is used */
 static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
     Scsi_Cmnd *tmp;
     unsigned long flags;
-    extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
     switch (cmd->cmnd[0]) {
@@ -942,15 +943,15 @@
 	    case WRITE:
 	    case WRITE_6:
 	    case WRITE_10:
-		hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
-		hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+		hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
 		hostdata->pendingw++;
 		break;
 	    case READ:
 	    case READ_6:
 	    case READ_10:
-		hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
-		hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+		hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
 		hostdata->pendingr++;
 		break;
 	}
@@ -1014,7 +1015,7 @@
     if (in_interrupt() || ((flags >> 8) & 7) >= 6)
 	queue_main();
     else
-	NCR5380_main();
+	NCR5380_main(NULL);
     return 0;
 }
 
@@ -1030,7 +1031,7 @@
  *  reenable them.  This prevents reentrancy and kernel stack overflow.
  */ 	
     
-static void NCR5380_main (void)
+static void NCR5380_main (void *bl)
 {
     Scsi_Cmnd *tmp, *prev;
     struct Scsi_Host *instance = first_instance;
@@ -1065,7 +1066,7 @@
 
     local_save_flags(flags);
     do {
-	local_irq_disable(flags); /* Freeze request queues */
+	local_irq_disable(); /* Freeze request queues */
 	done = 1;
 	
 	if (!hostdata->connected) {
@@ -1095,7 +1096,7 @@
 #ifdef SUPPORT_TAGS
 		    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
 #else
-		    !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+		    !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
 #endif
 		    ) {
 		    /* ++guenther: just to be sure, this must be atomic */
@@ -1217,8 +1218,8 @@
 					    BASR_ACK)) ==
        (BASR_PHASE_MATCH | BASR_ACK)) {
 	    printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG));
-	    printk("scsi%d: bus stuck in data phase -- probably a
- single byte overrun!\n", HOSTNO); 
+	    printk("scsi%d: bus stuck in data phase -- probably a single byte "
+		   "overrun!\n", HOSTNO);
 	    printk("not prepared for this error!\n");
 	    printk("please e-mail sammy@sammy.net with a description of how this\n");
 	    printk("error was produced.\n");
@@ -1349,15 +1350,15 @@
 	    case WRITE:
 	    case WRITE_6:
 	    case WRITE_10:
-		hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
-		/*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
 		hostdata->pendingw--;
 		break;
 	    case READ:
 	    case READ_6:
 	    case READ_10:
-		hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
-		/*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
 		hostdata->pendingr--;
 		break;
 	}
@@ -1518,7 +1519,7 @@
      * the host and target ID's on the SCSI bus.
      */
 
-    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
 
     /* 
      * Raise ATN while SEL is true before BSY goes false from arbitration,
@@ -1571,7 +1572,7 @@
 
     udelay(1);
 
-    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
 
     /* 
      * The SCSI specification calls for a 250 ms timeout for the actual 
@@ -1622,7 +1623,7 @@
 
     if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	if (hostdata->targets_present & (1 << cmd->target)) {
+	if (hostdata->targets_present & (1 << cmd->device->id)) {
 	    printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
 	    if (hostdata->restart_select)
 		printk(KERN_NOTICE "\trestart select\n");
@@ -1644,7 +1645,7 @@
 	return 0;
     } 
 
-    hostdata->targets_present |= (1 << cmd->target);
+    hostdata->targets_present |= (1 << cmd->device->id);
 
     /*
      * Since we followed the SCSI spec, and raised ATN while SEL 
@@ -1665,8 +1666,8 @@
     while (!(NCR5380_read(STATUS_REG) & SR_REQ));
 
     SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
-	       HOSTNO, cmd->target);
-    tmp[0] = IDENTIFY(1, cmd->lun);
+	       HOSTNO, cmd->device->id);
+    tmp[0] = IDENTIFY(1, cmd->device->lun);
 
 #ifdef SUPPORT_TAGS
     if (cmd->tag != TAG_NONE) {
@@ -1688,7 +1689,7 @@
     /* XXX need to handle errors here */
     hostdata->connected = cmd;
 #ifndef SUPPORT_TAGS
-    hostdata->busy[cmd->target] |= (1 << cmd->lun);
+    hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
 #endif    
 #ifdef SUN3_SCSI_VME
     dregs->csr |= CSR_INTR;
@@ -2103,7 +2104,7 @@
 			 * polled-IO. */ 
 			printk(KERN_NOTICE "scsi%d: switching target %d "
 			       "lun %d to slow handshake\n", HOSTNO,
-			       cmd->target, cmd->lun);
+			       cmd->device->id, cmd->device->lun);
 			cmd->device->borken = 1;
 			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
 			    ICR_ASSERT_ATN);
@@ -2161,7 +2162,7 @@
 		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 		    
 		    LNK_PRINTK("scsi%d: target %d lun %d linked command "
-			       "complete.\n", HOSTNO, cmd->target, cmd->lun);
+			       "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
 
 		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -2174,7 +2175,7 @@
 		    if (!cmd->next_link) {
 			 printk(KERN_NOTICE "scsi%d: target %d lun %d "
 				"linked command complete, no next_link\n",
-				HOSTNO, cmd->target, cmd->lun);
+				HOSTNO, cmd->device->id, cmd->device->lun);
 			    sink = 1;
 			    do_abort (instance);
 			    return;
@@ -2187,7 +2188,7 @@
 		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
 		    LNK_PRINTK("scsi%d: target %d lun %d linked request "
 			       "done, calling scsi_done().\n",
-			       HOSTNO, cmd->target, cmd->lun);
+			       HOSTNO, cmd->device->id, cmd->device->lun);
 #ifdef NCR5380_STATS
 		    collect_stats(hostdata, cmd);
 #endif
@@ -2201,7 +2202,7 @@
 		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 		    hostdata->connected = NULL;
 		    QU_PRINTK("scsi%d: command for target %d, lun %d "
-			      "completed\n", HOSTNO, cmd->target, cmd->lun);
+			      "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
 #ifdef SUPPORT_TAGS
 		    cmd_free_tag( cmd );
 		    if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
@@ -2213,16 +2214,16 @@
 			 */
 			/* ++Andreas: the mid level code knows about
 			   QUEUE_FULL now. */
-			TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+			TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
 			TAG_PRINTK("scsi%d: target %d lun %d returned "
 				   "QUEUE_FULL after %d commands\n",
-				   HOSTNO, cmd->target, cmd->lun,
+				   HOSTNO, cmd->device->id, cmd->device->lun,
 				   ta->nr_allocated);
 			if (ta->queue_size > ta->nr_allocated)
 			    ta->nr_allocated = ta->queue_size;
 		    }
 #else
-		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
 		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -2312,12 +2313,12 @@
 			 * the command is treated as untagged further on.
 			 */
 			cmd->device->tagged_supported = 0;
-			hostdata->busy[cmd->target] |= (1 << cmd->lun);
+			hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
 			cmd->tag = TAG_NONE;
 			TAG_PRINTK("scsi%d: target %d lun %d rejected "
 				   "QUEUE_TAG message; tagged queuing "
 				   "disabled\n",
-				   HOSTNO, cmd->target, cmd->lun);
+				   HOSTNO, cmd->device->id, cmd->device->lun);
 			break;
 		    }
 		    break;
@@ -2334,7 +2335,7 @@
 		    QU_PRINTK("scsi%d: command for target %d lun %d was "
 			      "moved from connected to the "
 			      "disconnected_queue\n", HOSTNO, 
-			      cmd->target, cmd->lun);
+			      cmd->device->id, cmd->device->lun);
 		    /* 
 		     * Restore phase bits to 0 so an interrupted selection, 
 		     * arbitration can resume.
@@ -2436,13 +2437,13 @@
 		    } else if (tmp != EXTENDED_MESSAGE)
 			printk(KERN_DEBUG "scsi%d: rejecting unknown "
 			       "message %02x from target %d, lun %d\n",
-			       HOSTNO, tmp, cmd->target, cmd->lun);
+			       HOSTNO, tmp, cmd->device->id, cmd->device->lun);
 		    else
 			printk(KERN_DEBUG "scsi%d: rejecting unknown "
 			       "extended message "
 			       "code %02x, length %d from target %d, lun %d\n",
 			       HOSTNO, extended_msg[1], extended_msg[0],
-			       cmd->target, cmd->lun);
+			       cmd->device->id, cmd->device->lun);
    
 
 		    msgout = MESSAGE_REJECT;
@@ -2460,7 +2461,7 @@
 #ifdef SUPPORT_TAGS
 		    cmd_free_tag( cmd );
 #else
-		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
 		    hostdata->connected = NULL;
 		    cmd->result = DID_ERROR << 16;
@@ -2579,7 +2580,7 @@
 
     for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
 	 tmp; prev = tmp, tmp = NEXT(tmp) ) {
-	if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+	if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
 #ifdef SUPPORT_TAGS
 	    && (tag == tmp->tag) 
 #endif
@@ -2686,7 +2687,7 @@
 
 static int NCR5380_abort (Scsi_Cmnd *cmd)
 {
-    struct Scsi_Host *instance = cmd->host;
+    struct Scsi_Host *instance = cmd->device->host;
     SETUP_HOSTDATA(instance);
     Scsi_Cmnd *tmp, **prev;
     unsigned long flags;
@@ -2736,7 +2737,7 @@
 #ifdef SUPPORT_TAGS
 	  cmd_free_tag( cmd );
 #else
-	  hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+	  hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
 	  local_irq_restore(flags);
 	  cmd->scsi_done(cmd);
@@ -2841,7 +2842,7 @@
 #ifdef SUPPORT_TAGS
 		    cmd_free_tag( tmp );
 #else
-		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
 		    local_irq_restore(flags);
 		    tmp->scsi_done(tmp);
@@ -2868,7 +2869,7 @@
 
 
 /* 
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
  * 
  * Purpose : reset the SCSI bus.
  *
@@ -2876,9 +2877,9 @@
  *
  */ 
 
-static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
 {
-    SETUP_HOSTDATA(cmd->host);
+    SETUP_HOSTDATA(cmd->device->host);
     int           i;
     unsigned long flags;
 #if 1
@@ -2886,7 +2887,7 @@
 #endif
 
 
-    NCR5380_print_status (cmd->host);
+    NCR5380_print_status (cmd->device->host);
 
     /* get in phase */
     NCR5380_write( TARGET_COMMAND_REG,
diff -urN linux-2.5.65-bk1/drivers/scsi/sun3_scsi.c linux-2.5.65-bk2/drivers/scsi/sun3_scsi.c
--- linux-2.5.65-bk1/drivers/scsi/sun3_scsi.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/drivers/scsi/sun3_scsi.c	Mon Mar 31 12:39:50 2003
@@ -79,6 +79,8 @@
 #include "sun3_scsi.h"
 #include "NCR5380.h"
 
+static void NCR5380_print(struct Scsi_Host *instance);
+
 /* #define OLDDMA */
 
 #define USE_WRAPPER
@@ -312,7 +314,7 @@
 	if (shpnt->irq != IRQ_NONE)
 		free_irq (shpnt->irq, NULL);
 
-	iounmap(sun3_scsi_regp);
+	iounmap((void *)sun3_scsi_regp);
 
 	return 0;
 }
@@ -621,8 +623,8 @@
 	.release		= sun3scsi_release,
 	.info			= sun3scsi_info,
 	.queuecommand		= sun3scsi_queue_command,
-	.abort			= sun3scsi_abort,
-	.reset			= sun3scsi_reset,
+	.eh_abort_handler      	= sun3scsi_abort,
+	.eh_bus_reset_handler  	= sun3scsi_bus_reset,
 	.can_queue		= CAN_QUEUE,
 	.this_id		= 7,
 	.sg_tablesize		= SG_TABLESIZE,
diff -urN linux-2.5.65-bk1/drivers/scsi/sun3_scsi.h linux-2.5.65-bk2/drivers/scsi/sun3_scsi.h
--- linux-2.5.65-bk1/drivers/scsi/sun3_scsi.h	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/drivers/scsi/sun3_scsi.h	Mon Mar 31 12:39:50 2003
@@ -55,7 +55,7 @@
 static int sun3scsi_abort (Scsi_Cmnd *);
 static int sun3scsi_detect (Scsi_Host_Template *);
 static const char *sun3scsi_info (struct Scsi_Host *);
-static int sun3scsi_reset(Scsi_Cmnd *, unsigned int);
+static int sun3scsi_bus_reset(Scsi_Cmnd *);
 static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int sun3scsi_proc_info (char *buffer, char **start, off_t offset,
 			int length, int hostno, int inout);
@@ -109,7 +109,7 @@
 
 #define NCR5380_intr sun3scsi_intr
 #define NCR5380_queue_command sun3scsi_queue_command
-#define NCR5380_reset sun3scsi_reset
+#define NCR5380_bus_reset sun3scsi_bus_reset
 #define NCR5380_abort sun3scsi_abort
 #define NCR5380_proc_info sun3scsi_proc_info
 #define NCR5380_dma_xfer_len(i, cmd, phase) \
diff -urN linux-2.5.65-bk1/drivers/scsi/sun3_scsi_vme.c linux-2.5.65-bk2/drivers/scsi/sun3_scsi_vme.c
--- linux-2.5.65-bk1/drivers/scsi/sun3_scsi_vme.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/drivers/scsi/sun3_scsi_vme.c	Mon Mar 31 12:39:50 2003
@@ -1,4 +1,4 @@
-/*
+ /*
  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
  *
  * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
@@ -566,8 +566,8 @@
 	.release		= sun3scsi_release,
 	.info			= sun3scsi_info,
 	.queuecommand		= sun3scsi_queue_command,
-	.abort			= sun3scsi_abort,
-	.reset			= sun3scsi_reset,
+	.eh_abort_handler      	= sun3scsi_abort,
+	.eh_bus_reset_handler  	= sun3scsi_bus_reset,
 	.can_queue		= CAN_QUEUE,
 	.this_id		= 7,
 	.sg_tablesize		= SG_TABLESIZE,
diff -urN linux-2.5.65-bk1/drivers/scsi/sun3x_esp.c linux-2.5.65-bk2/drivers/scsi/sun3x_esp.c
--- linux-2.5.65-bk1/drivers/scsi/sun3x_esp.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/drivers/scsi/sun3x_esp.c	Mon Mar 31 12:39:50 2003
@@ -374,11 +374,44 @@
     sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
 }
 
+
+static int esp_slave_alloc(Scsi_Device *SDptr)
+{
+	struct esp_device *esp_dev =
+		kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+
+	if (!esp_dev)
+		return -ENOMEM;
+	memset(esp_dev, 0, sizeof(struct esp_device));
+	SDptr->hostdata = esp_dev;
+	return 0;
+}
+
+static void esp_slave_destroy(Scsi_Device *SDptr)
+{
+	struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata;
+
+	esp->targets_present &= ~(1 << SDptr->id);
+	kfree(SDptr->hostdata);
+	SDptr->hostdata = NULL;
+}
+
+
+static int sun3x_esp_release(struct Scsi_Host *instance)
+{
+	/* this code does not support being compiled as a module */	 
+	return 1;
+
+}
+
 static Scsi_Host_Template driver_template = {
 	.proc_name		= "esp",
 	.proc_info		= &esp_proc_info,
 	.name			= "Sun ESP 100/100a/200",
 	.detect			= sun3x_esp_detect,
+	.release                = sun3x_esp_release,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
 	.info			= esp_info,
 	.command		= esp_command,
 	.queuecommand		= esp_queue,
diff -urN linux-2.5.65-bk1/drivers/scsi/wd33c93.c linux-2.5.65-bk2/drivers/scsi/wd33c93.c
--- linux-2.5.65-bk1/drivers/scsi/wd33c93.c	Mon Mar 17 13:44:19 2003
+++ linux-2.5.65-bk2/drivers/scsi/wd33c93.c	Mon Mar 31 12:39:51 2003
@@ -1471,7 +1471,7 @@
 		int busycount = 0;
 		extern void sgiwd93_reset(unsigned long);
 		/* wait 'til the chip gets some time for us */
-		while ((READ_AUX_STAT() & ASR_BSY) && busycount++ < 100)
+		while ((read_aux_stat(regs) & ASR_BSY) && busycount++ < 100)
 			udelay (10);
 	/*
  	 * there are scsi devices out there, which manage to lock up
@@ -1481,7 +1481,7 @@
 	 * does this for the SGI Indy, where this is possible
 	 */
 	/* still busy ? */
-	if (READ_AUX_STAT() & ASR_BSY)
+	if (read_aux_stat(regs) & ASR_BSY)
 		sgiwd93_reset(instance->base); /* yeah, give it the hard one */
 	}
 #endif
@@ -2086,3 +2086,4 @@
 EXPORT_SYMBOL(wd33c93_abort);
 EXPORT_SYMBOL(wd33c93_queuecommand);
 EXPORT_SYMBOL(wd33c93_intr);
+EXPORT_SYMBOL(wd33c93_proc_info);
diff -urN linux-2.5.65-bk1/drivers/serial/uart00.c linux-2.5.65-bk2/drivers/serial/uart00.c
--- linux-2.5.65-bk1/drivers/serial/uart00.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/drivers/serial/uart00.c	Mon Mar 31 12:39:51 2003
@@ -235,8 +235,8 @@
 
 	status = UART_GET_MSR(port);
 
-	if (!status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | 
-		       UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK))
+	if (!(status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | 
+			UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK)))
 		return;
 
 	if (status & UART_MSR_DDCD_MSK)
diff -urN linux-2.5.65-bk1/drivers/usb/core/hub.c linux-2.5.65-bk2/drivers/usb/core/hub.c
--- linux-2.5.65-bk1/drivers/usb/core/hub.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/usb/core/hub.c	Mon Mar 31 12:39:51 2003
@@ -1175,7 +1175,7 @@
 int usb_reset_device(struct usb_device *dev)
 {
 	struct usb_device *parent = dev->parent;
-	struct usb_device_descriptor descriptor;
+	struct usb_device_descriptor *descriptor;
 	int i, ret, port = -1;
 
 	if (!parent) {
@@ -1224,17 +1224,24 @@
 	 * If nothing changed, we reprogram the configuration and then
 	 * the alternate settings.
 	 */
-	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor,
-			sizeof(descriptor));
-	if (ret < 0)
+	descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);
+	if (!descriptor) {
+		return -ENOMEM;
+	}
+	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,
+			sizeof(*descriptor));
+	if (ret < 0) {
+		kfree(descriptor);
 		return ret;
+	}
 
-	le16_to_cpus(&descriptor.bcdUSB);
-	le16_to_cpus(&descriptor.idVendor);
-	le16_to_cpus(&descriptor.idProduct);
-	le16_to_cpus(&descriptor.bcdDevice);
+	le16_to_cpus(&descriptor->bcdUSB);
+	le16_to_cpus(&descriptor->idVendor);
+	le16_to_cpus(&descriptor->idProduct);
+	le16_to_cpus(&descriptor->bcdDevice);
 
-	if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) {
+	if (memcmp(&dev->descriptor, descriptor, sizeof(*descriptor))) {
+		kfree(descriptor);
 		usb_destroy_configuration(dev);
 
 		ret = usb_get_device_descriptor(dev);
@@ -1268,6 +1275,8 @@
 		return 1;
 	}
 
+	kfree(descriptor);
+
 	ret = usb_set_configuration(dev, dev->actconfig->desc.bConfigurationValue);
 	if (ret < 0) {
 		err("failed to set dev %s active configuration (error=%d)",
diff -urN linux-2.5.65-bk1/drivers/usb/core/message.c linux-2.5.65-bk2/drivers/usb/core/message.c
--- linux-2.5.65-bk1/drivers/usb/core/message.c	Mon Mar 17 13:43:48 2003
+++ linux-2.5.65-bk2/drivers/usb/core/message.c	Mon Mar 31 12:39:51 2003
@@ -88,7 +88,7 @@
 	int retv;
 	int length;
 
-	urb = usb_alloc_urb(0, GFP_KERNEL);
+	urb = usb_alloc_urb(0, GFP_NOIO);
 	if (!urb)
 		return -ENOMEM;
   
@@ -131,7 +131,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.5.65-bk1/drivers/usb/host/ehci-dbg.c linux-2.5.65-bk2/drivers/usb/host/ehci-dbg.c
--- linux-2.5.65-bk1/drivers/usb/host/ehci-dbg.c	Mon Mar 17 13:44:40 2003
+++ linux-2.5.65-bk2/drivers/usb/host/ehci-dbg.c	Mon Mar 31 12:39:51 2003
@@ -117,10 +117,10 @@
 static void __attribute__((__unused__))
 dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-	dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
-		qh, qh->hw_info1, qh->hw_info2,
+	dbg ("%s %p n%08x info1 %x info2 %x hw_curr %x qtd_next %x", label,
+		qh, qh->hw_next, qh->hw_info1, qh->hw_info2,
 		qh->hw_current, qh->hw_qtd_next);
-	dbg ("  alt+errs= %x, token= %x, page0= %x, page1= %x",
+	dbg ("  alt+nak+t= %x, token= %x, page0= %x, page1= %x",
 		qh->hw_alt_next, qh->hw_token,
 		qh->hw_buf [0], qh->hw_buf [1]);
 	if (qh->hw_buf [2]) {
diff -urN linux-2.5.65-bk1/drivers/usb/host/ehci-hcd.c linux-2.5.65-bk2/drivers/usb/host/ehci-hcd.c
--- linux-2.5.65-bk1/drivers/usb/host/ehci-hcd.c	Mon Mar 17 13:44:18 2003
+++ linux-2.5.65-bk2/drivers/usb/host/ehci-hcd.c	Mon Mar 31 12:39:51 2003
@@ -576,7 +576,7 @@
 	int			ports;
 	int			i;
 
-	dbg ("%s: suspend to %d", hcd_to_bus (hcd)->bus_name, state);
+	ehci_dbg (ehci, "suspend to %d\n", state);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -593,7 +593,7 @@
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_OWNER) != 0)
 			continue;
-dbg ("%s: suspend port %d", hcd_to_bus (hcd)->bus_name, i);
+		ehci_dbg (ehci, "suspend port %d", i);
 		temp |= PORT_SUSPEND;
 		writel (temp, &ehci->regs->port_status [i]);
 	}
@@ -615,7 +615,7 @@
 	int			ports;
 	int			i;
 
-	dbg ("%s: resume", hcd_to_bus (hcd)->bus_name);
+	ehci_dbg (ehci, "resume\n");
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -635,7 +635,7 @@
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_SUSPEND) != 0)
 			continue;
-dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i);
+		ehci_dbg (ehci, "resume port %d", i);
 		temp |= PORT_RESUME;
 		writel (temp, &ehci->regs->port_status [i]);
 		readl (&ehci->regs->command);	/* unblock posted writes */
@@ -880,8 +880,8 @@
 	/* ASSERT:  no requests/urbs are still linked (so no TDs) */
 	/* ASSERT:  nobody can be submitting urbs for this any more */
 
-	dbg ("%s: free_config devnum %d",
-		hcd_to_bus (hcd)->bus_name, udev->devnum);
+	ehci_dbg (ehci, "free_config %s devnum %d\n",
+			udev->devpath, udev->devnum);
 
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < 32; i++) {
@@ -912,7 +912,8 @@
 			dev->ep [i] = 0;
 			if (qh->qh_state == QH_STATE_IDLE)
 				goto idle;
-			dbg ("free_config, async ep 0x%02x qh %p", i, qh);
+			ehci_dbg (ehci, "free_config, async ep 0x%02x qh %p",
+					i, qh);
 
 			/* scan_async() empties the ring as it does its work,
 			 * using IAA, but doesn't (yet?) turn it off.  if it
diff -urN linux-2.5.65-bk1/drivers/usb/image/scanner.c linux-2.5.65-bk2/drivers/usb/image/scanner.c
--- linux-2.5.65-bk1/drivers/usb/image/scanner.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/drivers/usb/image/scanner.c	Mon Mar 31 12:39:51 2003
@@ -347,8 +347,9 @@
  *    - Don't print errors when the device is busy.
  *      
  * 0.4.11  2003-02-25
- *    - Added vendor/product ids for Artec, Avision, Brother, Medion, Primax,
- *      Prolink, Fujitsu, Plustek, and SYSCAN scanners.
+ *    - Added vendor/product ids for Artec, Avision, Brother, Canon, Compaq,
+ *      Fujitsu, Hewlett-Packard, Lexmark, LG Electronics, Medion, Microtek,
+ *      Primax, Prolink,  Plustek, SYSCAN, Trust and UMAX scanners.
  *    - Fixed generation of devfs names if dynamic minors are disabled.
  *    - Used kobject reference counting to free the scn struct when the device
  *      is closed and disconnected. Avoids crashes when writing to a 
diff -urN linux-2.5.65-bk1/drivers/usb/image/scanner.h linux-2.5.65-bk2/drivers/usb/image/scanner.h
--- linux-2.5.65-bk1/drivers/usb/image/scanner.h	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/drivers/usb/image/scanner.h	Mon Mar 31 12:39:51 2003
@@ -105,6 +105,7 @@
 	{ USB_DEVICE(0x0638, 0x0a10) },	/* iVina FB1600 (=Umax Astra 4500) */
 	/* Benq: see Acer */
 	/* Brother */
+	{ USB_DEVICE(0x04f9, 0x010f) },	/* MFC 5100C */
 	{ USB_DEVICE(0x04f9, 0x0111) },	/* MFC 6800 */
 	/* Canon */
 	{ USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */
@@ -118,9 +119,11 @@
 	{ USB_DEVICE(0x04a9, 0x220c) },	/* CanoScan D1250U2 */
 	{ USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */
 	{ USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */
+	{ USB_DEVICE(0x04a9, 0x2213) },	/* LIDE 50 */
 	{ USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */
 	/* Colorado -- See Primax/Colorado below */
 	/* Compaq */
+	{ USB_DEVICE(0x049f, 0x001a) },	/* S4 100 */
 	{ USB_DEVICE(0x049f, 0x0021) },	/* S200 */
 	/* Epson -- See Seiko/Epson below */
 	/* Fujitsu */
@@ -152,6 +155,8 @@
 	{ USB_DEVICE(0x03f0, 0x0705) }, /* ScanJet 4400C */
 	//	{ USB_DEVICE(0x03f0, 0x0801) },	/* ScanJet 7400C - NOT SUPPORTED - use hpusbscsi driver */
 	{ USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */
+	{ USB_DEVICE(0x03F0, 0x1005) },	/* ScanJet 5400C */
+	{ USB_DEVICE(0x03F0, 0x1105) },	/* ScanJet 5470C */
 	{ USB_DEVICE(0x03f0, 0x1305) },	/* Scanjet 4570c */
 	{ USB_DEVICE(0x03f0, 0x2005) },	/* ScanJet 3570c */
 	{ USB_DEVICE(0x03f0, 0x2205) },	/* ScanJet 3500c */
@@ -159,12 +164,16 @@
 	{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
 	/* Lexmark */
 	{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
+	{ USB_DEVICE(0x043d, 0x003d) }, /* X83 */
+	/* LG Electronics */
+	{ USB_DEVICE(0x0461, 0x0364) },	/* Scanworks 600U (repackaged Primax?) */
 	/* Medion */
 	{ USB_DEVICE(0x0461, 0x0377) },	/* MD 5345 - repackaged Primax? */
 	/* Memorex */
 	{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
 	/* Microtek */
 	{ USB_DEVICE(0x05da, 0x30ce) },	/* ScanMaker 3800 */
+	{ USB_DEVICE(0x05da, 0x30cf) },	/* ScanMaker 4800 */
 	/* The following SCSI-over-USB Microtek devices are supported by the
 	   microtek driver: Enable SCSI and USB Microtek in kernel config */
 	//	{ USB_DEVICE(0x05da, 0x0099) },	/* ScanMaker X6 - X6U */
@@ -259,7 +268,11 @@
 	{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
 	/* SYSCAN */
 	{ USB_DEVICE(0x0a82, 0x4600) }, /* TravelScan 460/464 */
+	/* Trust */
+	{ USB_DEVICE(0x05cb, 0x1483) }, /* CombiScan 19200 */
+	{ USB_DEVICE(0x05d8, 0x4006) }, /* Easy Webscan 19200 (repackaged Artec?) */
 	/* Umax */
+	{ USB_DEVICE(0x05d8, 0x4009) },	/* Astraslim (actually Artec?) */
 	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
 	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
 	{ USB_DEVICE(0x1606, 0x0060) }, /* Astra 3400U/3450U */
diff -urN linux-2.5.65-bk1/drivers/usb/input/hid-core.c linux-2.5.65-bk2/drivers/usb/input/hid-core.c
--- linux-2.5.65-bk1/drivers/usb/input/hid-core.c	Mon Mar 17 13:44:08 2003
+++ linux-2.5.65-bk2/drivers/usb/input/hid-core.c	Mon Mar 31 12:39:51 2003
@@ -1334,6 +1334,9 @@
 #define USB_VENDOR_ID_TANGTOP          0x0d3d
 #define USB_DEVICE_ID_TANGTOP_USBPS2   0x0001
 
+#define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5	0x0100
+
 struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
@@ -1377,6 +1380,7 @@
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
 	{ 0, 0 }
 };
 
diff -urN linux-2.5.65-bk1/drivers/usb/misc/Makefile linux-2.5.65-bk2/drivers/usb/misc/Makefile
--- linux-2.5.65-bk1/drivers/usb/misc/Makefile	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/drivers/usb/misc/Makefile	Mon Mar 31 12:39:51 2003
@@ -12,5 +12,3 @@
 obj-$(CONFIG_USB_TEST)		+= usbtest.o
 obj-$(CONFIG_USB_TIGL)		+= tiglusb.o
 obj-$(CONFIG_USB_USS720)	+= uss720.o
-
-speedtch-objs := speedtouch.o atmsar.o
diff -urN linux-2.5.65-bk1/drivers/usb/misc/atmsar.c linux-2.5.65-bk2/drivers/usb/misc/atmsar.c
--- linux-2.5.65-bk1/drivers/usb/misc/atmsar.c	Mon Mar 17 13:43:49 2003
+++ linux-2.5.65-bk2/drivers/usb/misc/atmsar.c	Wed Dec 31 16:00:00 1969
@@ -1,380 +0,0 @@
-/******************************************************************************
- *  atmsar.c  --  General SAR library for ATM devices.
- *
- *  Copyright (C) 2000, Johan Verrept
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- *  more details.
- *
- *  You should have received a copy of the GNU General Public License along with
- *  this program; if not, write to the Free Software Foundation, Inc., 59
- *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- ******************************************************************************/
-
-/*
- *  Written by Johan Verrept (Johan.Verrept@advalvas.be)
- *
- *  0.2.4A:	- Version for inclusion in 2.5 series kernel
- *		- Modifications by Richard Purdie (rpurdie@rpsys.net)
- *		- replaced "sarlib" with "atmsar"
- *		- adaptations for inclusion in kernel tree
- *
- *  0.2.4:	- Fixed wrong buffer overrun check in atmsar_decode_rawcell()
- *		reported by Stephen Robinson <stephen.robinson@zen.co.uk>
- *		- Fixed bug when input skb did not contain a multple of 52/53
- *		bytes (would happen when the speedtouch device resynced)
- *		also reported by Stephen Robinson <stephen.robinson@zen.co.uk>
- *
- *  0.2.3:	- Fixed wrong allocation size. caused memory corruption in some
- *		cases. Reported by Vladimir Dergachev <volodya@mindspring.com>
- *		- Added some comments
- *
- *  0.2.2:	- Fixed CRCASM
- *		patch from Linus Flannagan <linusf@netservices.eng.net>
- *		- Fixed problem when user did NOT use the
- *		ATMSAR_USE_53BYTE_CELL flag.
- *		reported by  Piers Scannell <email@lot105.com>
- *		- No more in-buffer rewriting for cloned buffers.
- *		- Removed the PII specific CFLAGS in the Makefile.
- *
- *  0.2.1:	- removed dependency on alloc_tx. tis presented problems when
- *		using this with the br2684 code.
- *
- *  0.2:	- added AAL0 reassembly
- *		- added alloc_tx support
- *		- replaced alloc_skb in decode functions to dev_alloc_skb to
- *		allow calling from interrupt
- *		- fixed embarassing AAL5 bug. I was setting the pti bit in the
- *		wrong byte...
- *		- fixed another emabrassing bug.. picked up the wrong crc type
- *		and forgot to invert the crc result...
- *		- fixed AAL5 length calculations.
- *		- removed automatic skb freeing from encode functions.
- *		This caused problems because i did kfree_skb it, while it
- *		needed to be popped. I cannot determine though whether it
- *		needs to be popped or not. Figu'e it out ye'self ;-)
- *		- added mru field. This is the buffersize. atmsar_decode_aal0
- *		will use when it allocates a receive buffer. A stop gap for
- *		real buffer management.
- *
- *  0.1:	- library created.
- *		- only contains AAL5, AAL0 can be easily added. (actually, only
- *		AAL0 reassembly is missing)
- *
- */
-
-#include <linux/crc32.h>
-#include "atmsar.h"
-
-/***********************
- **
- **  things to remember
- **
- ***********************/
-
-/*
-  1. the atmsar_vcc_data list pointer MUST be initialized to NULL
-  2. atmsar_encode_rawcell will drop incomplete cells.
-  3. ownership of the skb goes to the library !
-*/
-
-#define ATM_HDR_VPVC_MASK  (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
-
-/***********************
- **
- **  LOCAL STRUCTURES
- **
- ***********************/
-
-/***********************
- **
- **  LOCAL MACROS
- **
- ***********************/
-/*
-#define DEBUG 1
-*/
-#ifdef DEBUG
-#define PDEBUG(arg...)  printk(KERN_DEBUG "atmsar: " arg)
-#else
-#define PDEBUG(arg...)
-#endif
-
-#define ADD_HEADER(dest, header) \
-  *dest++ = (unsigned char) (header >> 24); \
-  *dest++ = (unsigned char) (header >> 16); \
-  *dest++ = (unsigned char) (header >> 8); \
-  *dest++ = (unsigned char) (header & 0xff);
-
-
-struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type,
-				     ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
-{
-	struct atmsar_vcc_data *new;
-
-	if (!vcc)
-		return NULL;
-
-	new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL);
-
-	if (!new)
-		return NULL;
-
-	memset (new, 0, sizeof (struct atmsar_vcc_data));
-	new->vcc = vcc;
-	new->stats = vcc->stats;
-	new->type = type;
-	new->next = NULL;
-	new->gfc = gfc;
-	new->vp = vpi;
-	new->vc = vci;
-	new->pti = pti;
-
-	switch (type) {
-	case ATMSAR_TYPE_AAL0:
-		new->mtu = ATMSAR_DEF_MTU_AAL0;
-		break;
-	case ATMSAR_TYPE_AAL1:
-		new->mtu = ATMSAR_DEF_MTU_AAL1;
-		break;
-	case ATMSAR_TYPE_AAL2:
-		new->mtu = ATMSAR_DEF_MTU_AAL2;
-		break;
-	case ATMSAR_TYPE_AAL34:
-		/* not supported */
-		new->mtu = ATMSAR_DEF_MTU_AAL34;
-		break;
-	case ATMSAR_TYPE_AAL5:
-		new->mtu = ATMSAR_DEF_MTU_AAL5;
-		break;
-	}
-
-	new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT)
-	    | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT)
-	    | ((unsigned long) vci << ATM_HDR_VCI_SHIFT)
-	    | ((unsigned long) pti << ATM_HDR_PTI_SHIFT);
-	new->flags = flags;
-	new->next = NULL;
-	new->reasBuffer = NULL;
-
-	new->next = *list;
-	*list = new;
-
-	PDEBUG ("Allocated new SARLib vcc 0x%p with vp %d vc %d\n", new, vpi, vci);
-
-	return new;
-}
-
-void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
-{
-	struct atmsar_vcc_data *work;
-
-	if (*list == vcc) {
-		*list = (*list)->next;
-	} else {
-		for (work = *list; work && work->next && (work->next != vcc); work = work->next);
-
-		/* return if not found */
-		if (work->next != vcc)
-			return;
-
-		work->next = work->next->next;
-	}
-
-	if (vcc->reasBuffer) {
-		dev_kfree_skb (vcc->reasBuffer);
-	}
-
-	PDEBUG ("Allocated SARLib vcc 0x%p with vp %d vc %d\n", vcc, vcc->vp, vcc->vc);
-
-	kfree (vcc);
-}
-
-
-/***********************
- **
- **  DECODE FUNCTIONS
- **
- ***********************/
-
-struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
-				       struct atmsar_vcc_data **ctx)
-{
-	while (skb->len) {
-		unsigned char *cell = skb->data;
-		unsigned char *cell_payload;
-		struct atmsar_vcc_data *vcc = list;
-		unsigned long atmHeader =
-		    ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) |
-		    ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff);
-
-		PDEBUG ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called\n", list, skb, ctx);
-		PDEBUG ("atmsar_decode_rawcell skb->data %p, skb->tail %p\n", skb->data, skb->tail);
-
-		if (!list || !skb || !ctx)
-			return NULL;
-		if (!skb->data || !skb->tail)
-			return NULL;
-
-		/* here should the header CRC check be... */
-
-		/* look up correct vcc */
-		for (;
-		     vcc
-		     && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK));
-		     vcc = vcc->next);
-
-		PDEBUG ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d\n", vcc,
-			(int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT),
-			(int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT));
-
-		if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) {
-			cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4);
-
-			switch (vcc->type) {
-			case ATMSAR_TYPE_AAL0:
-				/* case ATMSAR_TYPE_AAL1: when we have a decode AAL1 function... */
-				{
-					struct sk_buff *tmp = dev_alloc_skb (vcc->mtu);
-
-					if (tmp) {
-						memcpy (tmp->tail, cell_payload, 48);
-						skb_put (tmp, 48);
-
-						if (vcc->stats)
-							atomic_inc (&vcc->stats->rx);
-
-						skb_pull (skb,
-							  (vcc->
-							   flags & ATMSAR_USE_53BYTE_CELL ? 53 :
-							   52));
-						PDEBUG
-						    ("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL0 pdu 0x%p with length %d\n",
-						     tmp, tmp->len);
-						return tmp;
-					};
-				}
-				break;
-			case ATMSAR_TYPE_AAL1:
-			case ATMSAR_TYPE_AAL2:
-			case ATMSAR_TYPE_AAL34:
-				/* not supported */
-				break;
-			case ATMSAR_TYPE_AAL5:
-				if (!vcc->reasBuffer)
-					vcc->reasBuffer = dev_alloc_skb (vcc->mtu);
-
-				/* if alloc fails, we just drop the cell. it is possible that we can still
-				 * receive cells on other vcc's
-				 */
-				if (vcc->reasBuffer) {
-					/* if (buffer overrun) discard received cells until now */
-					if ((vcc->reasBuffer->len) > (vcc->mtu - 48))
-						skb_trim (vcc->reasBuffer, 0);
-
-					/* copy data */
-					memcpy (vcc->reasBuffer->tail, cell_payload, 48);
-					skb_put (vcc->reasBuffer, 48);
-
-					/* check for end of buffer */
-					if (cell[3] & 0x2) {
-						struct sk_buff *tmp;
-
-						/* the aal5 buffer ends here, cut the buffer. */
-						/* buffer will always have at least one whole cell, so */
-						/* don't need to check return from skb_pull */
-						skb_pull (skb,
-							  (vcc->
-							   flags & ATMSAR_USE_53BYTE_CELL ? 53 :
-							   52));
-						*ctx = vcc;
-						tmp = vcc->reasBuffer;
-						vcc->reasBuffer = NULL;
-
-						PDEBUG
-						    ("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL5 pdu 0x%p with length %d\n",
-						     tmp, tmp->len);
-						return tmp;
-					}
-				}
-				break;
-			};
-			/* flush the cell */
-			/* buffer will always contain at least one whole cell, so don't */
-			/* need to check return value from skb_pull */
-			skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52));
-		} else {
-			/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
-			if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
-			    NULL)
-				return NULL;
-		}
-	}
-
-	return NULL;
-};
-
-struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
-{
-	uint crc = 0xffffffff;
-	uint length, pdu_crc, pdu_length;
-
-	PDEBUG ("atmsar_decode_aal5 (0x%p, 0x%p) called\n", ctx, skb);
-
-	if (skb->len && (skb->len % 48))
-		return NULL;
-
-	length = (skb->tail[-6] << 8) + skb->tail[-5];
-	pdu_crc =
-	    (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
-	pdu_length = ((length + 47 + 8) / 48) * 48;
-
-	PDEBUG ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d\n",
-		skb->len, length, pdu_crc, pdu_length);
-
-	/* is skb long enough ? */
-	if (skb->len < pdu_length) {
-		if (ctx->stats)
-			atomic_inc (&ctx->stats->rx_err);
-		return NULL;
-	}
-
-	/* is skb too long ? */
-	if (skb->len > pdu_length) {
-		PDEBUG ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d\n",
-			skb->len, pdu_length);
-		/* buffer is too long. we can try to recover
-		 * if we discard the first part of the skb.
-		 * the crc will decide whether this was ok
-		 */
-		skb_pull (skb, skb->len - pdu_length);
-	}
-
-	crc = ~crc32_be (crc, skb->data, pdu_length - 4);
-
-	/* check crc */
-	if (pdu_crc != crc) {
-		PDEBUG ("atmsar_decode_aal5: crc check failed!\n");
-		if (ctx->stats)
-			atomic_inc (&ctx->stats->rx_err);
-		return NULL;
-	}
-
-	/* pdu is ok */
-	skb_trim (skb, length);
-
-	/* update stats */
-	if (ctx->stats)
-		atomic_inc (&ctx->stats->rx);
-
-	PDEBUG ("atmsar_decode_aal5 returns pdu 0x%p with length %d\n", skb, skb->len);
-	return skb;
-};
diff -urN linux-2.5.65-bk1/drivers/usb/misc/atmsar.h linux-2.5.65-bk2/drivers/usb/misc/atmsar.h
--- linux-2.5.65-bk1/drivers/usb/misc/atmsar.h	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/usb/misc/atmsar.h	Wed Dec 31 16:00:00 1969
@@ -1,87 +0,0 @@
-#ifndef _ATMSAR_H_
-#define _ATMSAR_H_
-
-/******************************************************************************
- *  atmsar.h  --  General SAR library for ATM devices.
- *
- *  Copyright (C) 2000, Johan Verrept
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- *  more details.
- *
- *  You should have received a copy of the GNU General Public License along with
- *  this program; if not, write to the Free Software Foundation, Inc., 59
- *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- ******************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/atmdev.h>
-#include <linux/skbuff.h>
-#include <linux/types.h>
-#include <linux/atm.h>
-
-#define ATMSAR_USE_53BYTE_CELL  0x1L
-#define ATMSAR_SET_PTI          0x2L
-
-#define ATM_CELL_HEADER		(ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
-
-/* types */
-#define ATMSAR_TYPE_AAL0        ATM_AAL0
-#define ATMSAR_TYPE_AAL1        ATM_AAL1
-#define ATMSAR_TYPE_AAL2        ATM_AAL2
-#define ATMSAR_TYPE_AAL34       ATM_AAL34
-#define ATMSAR_TYPE_AAL5        ATM_AAL5
-
-
-/* default MTU's */
-#define ATMSAR_DEF_MTU_AAL0         48
-#define ATMSAR_DEF_MTU_AAL1         47
-#define ATMSAR_DEF_MTU_AAL2          0	/* not supported */
-#define ATMSAR_DEF_MTU_AAL34         0	/* not supported */
-#define ATMSAR_DEF_MTU_AAL5      65535	/* max mtu ..    */
-
-struct atmsar_vcc_data {
-	struct atmsar_vcc_data *next;
-
-	/* general atmsar flags, per connection */
-	int flags;
-	int type;
-
-	/* connection specific non-atmsar data */
-	struct atm_vcc *vcc;
-	struct k_atm_aal_stats *stats;
-	unsigned short mtu;	/* max is actually  65k for AAL5... */
-
-	/* cell data */
-	unsigned int vp;
-	unsigned int vc;
-	unsigned char gfc;
-	unsigned char pti;
-	unsigned int headerFlags;
-	unsigned long atmHeader;
-
-	/* raw cell reassembly */
-	struct sk_buff *reasBuffer;
-};
-
-
-extern struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc,
-					    uint type, ushort vpi, ushort vci, unchar pti,
-					    unchar gfc, uint flags);
-extern void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc);
-
-struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
-				       struct atmsar_vcc_data **ctx);
-struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
-
-#endif				/* _ATMSAR_H_ */
diff -urN linux-2.5.65-bk1/drivers/usb/misc/speedtch.c linux-2.5.65-bk2/drivers/usb/misc/speedtch.c
--- linux-2.5.65-bk1/drivers/usb/misc/speedtch.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/drivers/usb/misc/speedtch.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,1514 @@
+/******************************************************************************
+ *  speedtouch.c  --  Alcatel SpeedTouch USB xDSL modem driver.
+ *
+ *  Copyright (C) 2001, Alcatel
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ ******************************************************************************/
+
+/*
+ *  Written by Johan Verrept (Johan.Verrept@advalvas.be)
+ *
+ *  1.5A:	- Version for inclusion in 2.5 series kernel
+ *		- Modifications by Richard Purdie (rpurdie@rpsys.net)
+ *		- made compatible with kernel 2.5.6 onwards by changing
+ *		udsl_usb_send_data_context->urb to a pointer and adding code
+ *		to alloc and free it
+ *		- remove_wait_queue() added to udsl_atm_processqueue_thread()
+ *
+ *  1.5:	- fixed memory leak when atmsar_decode_aal5 returned NULL.
+ *		(reported by stephen.robinson@zen.co.uk)
+ *
+ *  1.4:	- changed the spin_lock() under interrupt to spin_lock_irqsave()
+ *		- unlink all active send urbs of a vcc that is being closed.
+ *
+ *  1.3.1:	- added the version number
+ *
+ *  1.3:	- Added multiple send urb support
+ *		- fixed memory leak and vcc->tx_inuse starvation bug
+ *		  when not enough memory left in vcc.
+ *
+ *  1.2:	- Fixed race condition in udsl_usb_send_data()
+ *  1.1:	- Turned off packet debugging
+ *
+ */
+
+#include <asm/semaphore.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/crc32.h>
+
+/*
+#define DEBUG 1
+#define DEBUG_PACKET 1
+*/
+
+#include <linux/usb.h>
+
+
+#ifdef DEBUG_PACKET
+static int udsl_print_packet (const unsigned char *data, int len);
+#define PACKETDEBUG(arg...) udsl_print_packet (arg)
+#else
+#define PACKETDEBUG(arg...)
+#endif
+
+#define DRIVER_AUTHOR	"Johan Verrept, Johan.Verrept@advalvas.be"
+#define DRIVER_DESC	"Driver for the Alcatel SpeedTouch USB ADSL modem"
+#define DRIVER_VERSION	"1.5A"
+
+#define SPEEDTOUCH_VENDORID		0x06b9
+#define SPEEDTOUCH_PRODUCTID		0x4061
+
+#define UDSL_NUMBER_RCV_URBS		1
+#define UDSL_NUMBER_SND_URBS		1
+#define UDSL_NUMBER_SND_BUFS		(2*UDSL_NUMBER_SND_URBS)
+#define UDSL_RCV_BUFFER_SIZE		(1*64) /* ATM cells */
+#define UDSL_SND_BUFFER_SIZE		(1*64) /* ATM cells */
+/* max should be (1500 IP mtu + 2 ppp bytes + 32 * 5 cellheader overhead) for
+ * PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */
+#define UDSL_MAX_AAL5_MRU		2048
+
+#define UDSL_IOCTL_START		1
+#define UDSL_IOCTL_STOP			2
+
+/* endpoint declarations */
+
+#define UDSL_ENDPOINT_DATA_OUT		0x07
+#define UDSL_ENDPOINT_DATA_IN		0x87
+
+#define ATM_CELL_HEADER			(ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
+
+#define hex2int(c) ( (c >= '0')&&(c <= '9') ?  (c - '0') : ((c & 0xf)+9) )
+
+/* usb_device_id struct */
+
+static struct usb_device_id udsl_usb_ids [] = {
+	{ USB_DEVICE (SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID) },
+	{ }			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, udsl_usb_ids);
+
+/* context declarations */
+
+struct udsl_receiver {
+	struct list_head list;
+	struct sk_buff *skb;
+	struct urb *urb;
+	struct udsl_instance_data *instance;
+};
+
+struct udsl_send_buffer {
+	struct list_head list;
+	unsigned char *base;
+	unsigned char *free_start;
+	unsigned int free_cells;
+};
+
+struct udsl_sender {
+	struct list_head list;
+	struct udsl_send_buffer *buffer;
+	struct urb *urb;
+	struct udsl_instance_data *instance;
+};
+
+struct udsl_control {
+	struct atm_skb_data atm_data;
+	unsigned int num_cells;
+	unsigned int num_entire;
+	unsigned char cell_header [ATM_CELL_HEADER];
+	unsigned int pdu_padding;
+	unsigned char aal5_trailer [ATM_AAL5_TRAILER];
+};
+
+#define UDSL_SKB(x)		((struct udsl_control *)(x)->cb)
+
+struct atmsar_vcc_data {
+	struct atmsar_vcc_data *next;
+
+	/* general atmsar flags, per connection */
+	int flags;
+	int type;
+
+	/* connection specific non-atmsar data */
+	struct atm_vcc *vcc;
+	struct k_atm_aal_stats *stats;
+	unsigned short mtu;	/* max is actually  65k for AAL5... */
+
+	/* cell data */
+	unsigned int vp;
+	unsigned int vc;
+	unsigned char gfc;
+	unsigned char pti;
+	unsigned int headerFlags;
+	unsigned long atmHeader;
+
+	/* raw cell reassembly */
+	struct sk_buff *reasBuffer;
+};
+
+/*
+ * UDSL main driver data
+ */
+
+struct udsl_instance_data {
+	struct semaphore serialize;
+
+	/* usb device part */
+	struct usb_device *usb_dev;
+	char description [64];
+	int firmware_loaded;
+
+	/* atm device part */
+	struct atm_dev *atm_dev;
+	struct atmsar_vcc_data *atmsar_vcc_list;
+
+	/* receiving */
+	struct udsl_receiver all_receivers [UDSL_NUMBER_RCV_URBS];
+
+	spinlock_t spare_receivers_lock;
+	struct list_head spare_receivers;
+
+	spinlock_t completed_receivers_lock;
+	struct list_head completed_receivers;
+
+	struct tasklet_struct receive_tasklet;
+
+	/* sending */
+	struct udsl_sender all_senders [UDSL_NUMBER_SND_URBS];
+	struct udsl_send_buffer all_buffers [UDSL_NUMBER_SND_BUFS];
+
+	struct sk_buff_head sndqueue;
+
+	spinlock_t send_lock;
+	struct list_head spare_senders;
+	struct list_head spare_buffers;
+
+	struct tasklet_struct send_tasklet;
+	struct sk_buff *current_skb;			/* being emptied */
+	struct udsl_send_buffer *current_buffer;	/* being filled */
+	struct list_head filled_buffers;
+};
+
+static const char udsl_driver_name [] = "speedtch";
+
+/*
+ * atm driver prototypes and structures
+ */
+
+static void udsl_atm_dev_close (struct atm_dev *dev);
+static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci);
+static void udsl_atm_close (struct atm_vcc *vcc);
+static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg);
+static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb);
+static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page);
+
+static struct atmdev_ops udsl_atm_devops = {
+	.dev_close =	udsl_atm_dev_close,
+	.open =		udsl_atm_open,
+	.close =	udsl_atm_close,
+	.ioctl =	udsl_atm_ioctl,
+	.send =		udsl_atm_send,
+	.proc_read =	udsl_atm_proc_read,
+};
+
+/*
+ * usb driver prototypes and structures
+ */
+static int udsl_usb_probe (struct usb_interface *intf,
+			   const struct usb_device_id *id);
+static void udsl_usb_disconnect (struct usb_interface *intf);
+static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data);
+
+static struct usb_driver udsl_usb_driver = {
+	.name =		udsl_driver_name,
+	.probe =	udsl_usb_probe,
+	.disconnect =	udsl_usb_disconnect,
+	.ioctl =	udsl_usb_ioctl,
+	.id_table =	udsl_usb_ids,
+};
+
+
+/*************
+**  decode  **
+*************/
+
+#define ATM_HDR_VPVC_MASK		(ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
+#define ATMSAR_USE_53BYTE_CELL		0x1L
+
+struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
+				       struct atmsar_vcc_data **ctx)
+{
+	while (skb->len) {
+		unsigned char *cell = skb->data;
+		unsigned char *cell_payload;
+		struct atmsar_vcc_data *vcc = list;
+		unsigned long atmHeader =
+		    ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) |
+		    ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff);
+
+		dbg ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called", list, skb, ctx);
+		dbg ("atmsar_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail);
+
+		if (!list || !skb || !ctx)
+			return NULL;
+		if (!skb->data || !skb->tail)
+			return NULL;
+
+		/* here should the header CRC check be... */
+
+		/* look up correct vcc */
+		for (;
+		     vcc
+		     && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK));
+		     vcc = vcc->next);
+
+		dbg ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d", vcc,
+			(int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT),
+			(int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT));
+
+		if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) {
+			cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4);
+
+			switch (vcc->type) {
+			case ATM_AAL0:
+				/* case ATM_AAL1: when we have a decode AAL1 function... */
+				{
+					struct sk_buff *tmp = dev_alloc_skb (vcc->mtu);
+
+					if (tmp) {
+						memcpy (tmp->tail, cell_payload, 48);
+						skb_put (tmp, 48);
+
+						if (vcc->stats)
+							atomic_inc (&vcc->stats->rx);
+
+						skb_pull (skb,
+							  (vcc->
+							   flags & ATMSAR_USE_53BYTE_CELL ? 53 :
+							   52));
+						dbg
+						    ("atmsar_decode_rawcell returns ATM_AAL0 pdu 0x%p with length %d",
+						     tmp, tmp->len);
+						return tmp;
+					};
+				}
+				break;
+			case ATM_AAL1:
+			case ATM_AAL2:
+			case ATM_AAL34:
+				/* not supported */
+				break;
+			case ATM_AAL5:
+				if (!vcc->reasBuffer)
+					vcc->reasBuffer = dev_alloc_skb (vcc->mtu);
+
+				/* if alloc fails, we just drop the cell. it is possible that we can still
+				 * receive cells on other vcc's
+				 */
+				if (vcc->reasBuffer) {
+					/* if (buffer overrun) discard received cells until now */
+					if ((vcc->reasBuffer->len) > (vcc->mtu - 48))
+						skb_trim (vcc->reasBuffer, 0);
+
+					/* copy data */
+					memcpy (vcc->reasBuffer->tail, cell_payload, 48);
+					skb_put (vcc->reasBuffer, 48);
+
+					/* check for end of buffer */
+					if (cell[3] & 0x2) {
+						struct sk_buff *tmp;
+
+						/* the aal5 buffer ends here, cut the buffer. */
+						/* buffer will always have at least one whole cell, so */
+						/* don't need to check return from skb_pull */
+						skb_pull (skb,
+							  (vcc->
+							   flags & ATMSAR_USE_53BYTE_CELL ? 53 :
+							   52));
+						*ctx = vcc;
+						tmp = vcc->reasBuffer;
+						vcc->reasBuffer = NULL;
+
+						dbg
+						    ("atmsar_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d",
+						     tmp, tmp->len);
+						return tmp;
+					}
+				}
+				break;
+			};
+			/* flush the cell */
+			/* buffer will always contain at least one whole cell, so don't */
+			/* need to check return value from skb_pull */
+			skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52));
+		} else {
+			/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
+			if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
+			    NULL)
+				return NULL;
+		}
+	}
+
+	return NULL;
+};
+
+struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+{
+	uint crc = 0xffffffff;
+	uint length, pdu_crc, pdu_length;
+
+	dbg ("atmsar_decode_aal5 (0x%p, 0x%p) called", ctx, skb);
+
+	if (skb->len && (skb->len % 48))
+		return NULL;
+
+	length = (skb->tail[-6] << 8) + skb->tail[-5];
+	pdu_crc =
+	    (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
+	pdu_length = ((length + 47 + 8) / 48) * 48;
+
+	dbg ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d",
+		skb->len, length, pdu_crc, pdu_length);
+
+	/* is skb long enough ? */
+	if (skb->len < pdu_length) {
+		if (ctx->stats)
+			atomic_inc (&ctx->stats->rx_err);
+		return NULL;
+	}
+
+	/* is skb too long ? */
+	if (skb->len > pdu_length) {
+		dbg ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d",
+			skb->len, pdu_length);
+		/* buffer is too long. we can try to recover
+		 * if we discard the first part of the skb.
+		 * the crc will decide whether this was ok
+		 */
+		skb_pull (skb, skb->len - pdu_length);
+	}
+
+	crc = ~crc32_be (crc, skb->data, pdu_length - 4);
+
+	/* check crc */
+	if (pdu_crc != crc) {
+		dbg ("atmsar_decode_aal5: crc check failed!");
+		if (ctx->stats)
+			atomic_inc (&ctx->stats->rx_err);
+		return NULL;
+	}
+
+	/* pdu is ok */
+	skb_trim (skb, length);
+
+	/* update stats */
+	if (ctx->stats)
+		atomic_inc (&ctx->stats->rx);
+
+	dbg ("atmsar_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len);
+	return skb;
+};
+
+
+/*************
+**  encode  **
+*************/
+
+static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb) {
+	struct udsl_control *ctrl = UDSL_SKB (skb);
+	unsigned int i, zero_padding;
+	unsigned char zero = 0;
+	u32 crc;
+
+	ctrl->atm_data.vcc = vcc;
+	ctrl->cell_header [0] = vcc->vpi >> 4;
+	ctrl->cell_header [1] = (vcc->vpi << 4) | (vcc->vci >> 12);
+	ctrl->cell_header [2] = vcc->vci >> 4;
+	ctrl->cell_header [3] = vcc->vci << 4;
+	ctrl->cell_header [4] = 0xec;
+
+	ctrl->num_cells = (skb->len + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD;
+	ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
+
+	zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER;
+
+	if (ctrl->num_entire + 1 < ctrl->num_cells)
+		ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
+	else
+		ctrl->pdu_padding = zero_padding;
+
+	ctrl->aal5_trailer [0] = 0; /* UU = 0 */
+	ctrl->aal5_trailer [1] = 0; /* CPI = 0 */
+	ctrl->aal5_trailer [2] = skb->len >> 8;
+	ctrl->aal5_trailer [3] = skb->len;
+
+	crc = crc32_be (~0, skb->data, skb->len);
+	for (i = 0; i < zero_padding; i++)
+		crc = crc32_be (crc, &zero, 1);
+	crc = crc32_be (crc, ctrl->aal5_trailer, 4);
+	crc = ~crc;
+
+	ctrl->aal5_trailer [4] = crc >> 24;
+	ctrl->aal5_trailer [5] = crc >> 16;
+	ctrl->aal5_trailer [6] = crc >> 8;
+	ctrl->aal5_trailer [7] = crc;
+}
+
+unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb, unsigned char **target_p) {
+	struct udsl_control *ctrl = UDSL_SKB (skb);
+	unsigned char *target = *target_p;
+	unsigned int nc, ne, i;
+
+	dbg ("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding);
+
+	nc = ctrl->num_cells;
+	ne = min (howmany, ctrl->num_entire);
+
+	for (i = 0; i < ne; i++) {
+		memcpy (target, ctrl->cell_header, ATM_CELL_HEADER);
+		target += ATM_CELL_HEADER;
+		memcpy (target, skb->data, ATM_CELL_PAYLOAD);
+		target += ATM_CELL_PAYLOAD;
+		__skb_pull (skb, ATM_CELL_PAYLOAD);
+	}
+
+	ctrl->num_entire -= ne;
+
+	if (!(ctrl->num_cells -= ne) || !(howmany -= ne))
+		goto out;
+
+	memcpy (target, ctrl->cell_header, ATM_CELL_HEADER);
+	target += ATM_CELL_HEADER;
+	memcpy (target, skb->data, skb->len);
+	target += skb->len;
+	__skb_pull (skb, skb->len);
+	memset (target, 0, ctrl->pdu_padding);
+	target += ctrl->pdu_padding;
+
+	if (--ctrl->num_cells) {
+		if (!--howmany) {
+			ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
+			goto out;
+		}
+
+		memcpy (target, ctrl->cell_header, ATM_CELL_HEADER);
+		target += ATM_CELL_HEADER;
+		memset (target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
+		target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
+
+		if (--ctrl->num_cells)
+			BUG();
+	}
+
+	memcpy (target, ctrl->aal5_trailer, ATM_AAL5_TRAILER);
+	target += ATM_AAL5_TRAILER;
+	/* set pti bit in last cell */
+	*(target + 3 - ATM_CELL_SIZE) |= 0x2;
+
+out:
+	*target_p = target;
+	return nc - ctrl->num_cells;
+}
+
+
+/**************
+**  receive  **
+**************/
+
+static void udsl_complete_receive (struct urb *urb, struct pt_regs *regs)
+{
+	struct udsl_instance_data *instance;
+	struct udsl_receiver *rcv;
+	unsigned long flags;
+
+	if (!urb || !(rcv = urb->context) || !(instance = rcv->instance)) {
+		dbg ("udsl_complete_receive: bad urb!");
+		return;
+	}
+
+	dbg ("udsl_complete_receive entered (urb 0x%p, status %d)", urb, urb->status);
+
+	/* may not be in_interrupt() */
+	spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+	list_add_tail (&rcv->list, &instance->completed_receivers);
+	tasklet_schedule (&instance->receive_tasklet);
+	spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+}
+
+static void udsl_process_receive (unsigned long data)
+{
+	struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
+	struct udsl_receiver *rcv;
+	unsigned long flags;
+	unsigned char *data_start;
+	struct sk_buff *skb;
+	struct urb *urb;
+	struct atmsar_vcc_data *atmsar_vcc = NULL;
+	struct sk_buff *new = NULL, *tmp = NULL;
+	int err;
+
+	dbg ("udsl_process_receive entered");
+
+	spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+	while (!list_empty (&instance->completed_receivers)) {
+		rcv = list_entry (instance->completed_receivers.next, struct udsl_receiver, list);
+		list_del (&rcv->list);
+		spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+
+		urb = rcv->urb;
+		dbg ("udsl_process_receive: got packet %p with length %d and status %d", urb, urb->actual_length, urb->status);
+
+		switch (urb->status) {
+		case 0:
+			dbg ("udsl_process_receive: processing urb with rcv %p, urb %p, skb %p", rcv, urb, rcv->skb);
+
+			/* update the skb structure */
+			skb = rcv->skb;
+			skb_trim (skb, 0);
+			skb_put (skb, urb->actual_length);
+			data_start = skb->data;
+
+			dbg ("skb->len = %d", skb->len);
+			PACKETDEBUG (skb->data, skb->len);
+
+			while ((new =
+				atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
+						       &atmsar_vcc)) != NULL) {
+				dbg ("(after cell processing)skb->len = %d", new->len);
+
+				switch (atmsar_vcc->type) {
+				case ATM_AAL5:
+					tmp = new;
+					new = atmsar_decode_aal5 (atmsar_vcc, new);
+
+					/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
+					if (new) {
+						dbg ("(after aal5 decap) skb->len = %d", new->len);
+						if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
+							PACKETDEBUG (new->data, new->len);
+							atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
+						} else {
+							dbg
+							    ("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d",
+							     atomic_read (&atmsar_vcc->vcc->rx_inuse),
+							     atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
+							dev_kfree_skb (new);
+						}
+					} else {
+						dbg ("atmsar_decode_aal5 returned NULL!");
+						dev_kfree_skb (tmp);
+					}
+					break;
+				default:
+					/* not supported. we delete the skb. */
+					printk (KERN_INFO
+						"SpeedTouch USB: illegal vcc type. Dropping packet.\n");
+					dev_kfree_skb (new);
+					break;
+				}
+			}
+
+			/* restore skb */
+			skb_push (skb, skb->data - data_start);
+
+			usb_fill_bulk_urb (urb,
+					   instance->usb_dev,
+					   usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
+					   (unsigned char *) rcv->skb->data,
+					   UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE,
+					   udsl_complete_receive,
+					   rcv);
+			if (!(err = usb_submit_urb (urb, GFP_ATOMIC)))
+				break;
+			dbg ("udsl_process_receive: submission failed (%d)", err);
+			/* fall through */
+		default: /* error or urb unlinked */
+			dbg ("udsl_process_receive: adding to spare_receivers");
+			spin_lock_irqsave (&instance->spare_receivers_lock, flags);
+			list_add (&rcv->list, &instance->spare_receivers);
+			spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
+			break;
+		} /* switch */
+
+		spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+	} /* while */
+	spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+	dbg ("udsl_process_receive successful");
+}
+
+static void udsl_fire_receivers (struct udsl_instance_data *instance)
+{
+	struct list_head receivers, *pos, *n;
+	unsigned long flags;
+
+	INIT_LIST_HEAD (&receivers);
+
+	down (&instance->serialize);
+
+	spin_lock_irqsave (&instance->spare_receivers_lock, flags);
+	list_splice_init (&instance->spare_receivers, &receivers);
+	spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
+
+	list_for_each_safe (pos, n, &receivers) {
+		struct udsl_receiver *rcv = list_entry (pos, struct udsl_receiver, list);
+
+		dbg ("udsl_fire_receivers: firing urb %p", rcv->urb);
+
+		usb_fill_bulk_urb (rcv->urb,
+				   instance->usb_dev,
+				   usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
+				   (unsigned char *) rcv->skb->data,
+				   UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE,
+				   udsl_complete_receive,
+				   rcv);
+
+		if (usb_submit_urb (rcv->urb, GFP_KERNEL) < 0) {
+			dbg ("udsl_fire_receivers: submit failed!");
+			spin_lock_irqsave (&instance->spare_receivers_lock, flags);
+			list_move (pos, &instance->spare_receivers);
+			spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
+		}
+	}
+
+	up (&instance->serialize);
+}
+
+
+/***********
+**  send  **
+***********/
+
+static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
+{
+	struct udsl_instance_data *instance;
+	struct udsl_sender *snd;
+	unsigned long flags;
+
+	if (!urb || !(snd = urb->context) || !(instance = snd->instance)) {
+		dbg ("udsl_complete_send: bad urb!");
+		return;
+	}
+
+	dbg ("udsl_complete_send entered (urb 0x%p, status %d)", urb, urb->status);
+
+	/* may not be in_interrupt() */
+	spin_lock_irqsave (&instance->send_lock, flags);
+	list_add (&snd->list, &instance->spare_senders);
+	list_add (&snd->buffer->list, &instance->spare_buffers);
+	tasklet_schedule (&instance->send_tasklet);
+	spin_unlock_irqrestore (&instance->send_lock, flags);
+}
+
+static void udsl_process_send (unsigned long data)
+{
+	struct udsl_send_buffer *buf;
+	int err;
+	unsigned long flags;
+	struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
+	unsigned int num_written;
+	struct sk_buff *skb;
+	struct udsl_sender *snd;
+
+	dbg ("udsl_process_send entered");
+
+made_progress:
+	spin_lock_irqsave (&instance->send_lock, flags);
+	while (!list_empty (&instance->spare_senders)) {
+		if (!list_empty (&instance->filled_buffers)) {
+			buf = list_entry (instance->filled_buffers.next, struct udsl_send_buffer, list);
+			list_del (&buf->list);
+			dbg ("sending filled buffer (0x%p)", buf);
+		} else if ((buf = instance->current_buffer)) {
+			instance->current_buffer = NULL;
+			dbg ("sending current buffer (0x%p)", buf);
+		} else /* all buffers empty */
+			break;
+
+		snd = list_entry (instance->spare_senders.next, struct udsl_sender, list);
+		list_del (&snd->list);
+		spin_unlock_irqrestore (&instance->send_lock, flags);
+
+		snd->buffer = buf;
+	        usb_fill_bulk_urb (snd->urb,
+				   instance->usb_dev,
+				   usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
+				   buf->base,
+				   (UDSL_SND_BUFFER_SIZE - buf->free_cells) * ATM_CELL_SIZE,
+				   udsl_complete_send,
+				   snd);
+
+		dbg ("submitting urb 0x%p, contains %d cells", snd->urb, UDSL_SND_BUFFER_SIZE - buf->free_cells);
+
+		if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) {
+			dbg ("submission failed (%d)!", err);
+			spin_lock_irqsave (&instance->send_lock, flags);
+			list_add (&snd->list, &instance->spare_senders);
+			spin_unlock_irqrestore (&instance->send_lock, flags);
+			list_add (&buf->list, &instance->filled_buffers);
+			return;
+		}
+
+		spin_lock_irqsave (&instance->send_lock, flags);
+	} /* while */
+	spin_unlock_irqrestore (&instance->send_lock, flags);
+
+	if (!instance->current_skb && !(instance->current_skb = skb_dequeue (&instance->sndqueue))) {
+		dbg ("done - no more skbs");
+		return;
+	}
+
+	skb = instance->current_skb;
+
+	if (!(buf = instance->current_buffer)) {
+		spin_lock_irqsave (&instance->send_lock, flags);
+		if (list_empty (&instance->spare_buffers)) {
+			instance->current_buffer = NULL;
+			spin_unlock_irqrestore (&instance->send_lock, flags);
+			dbg ("done - no more buffers");
+			return;
+		}
+		buf = list_entry (instance->spare_buffers.next, struct udsl_send_buffer, list);
+		list_del (&buf->list);
+		spin_unlock_irqrestore (&instance->send_lock, flags);
+
+		buf->free_start = buf->base;
+		buf->free_cells = UDSL_SND_BUFFER_SIZE;
+
+		instance->current_buffer = buf;
+	}
+
+	num_written = udsl_write_cells (buf->free_cells, skb, &buf->free_start);
+
+	dbg ("wrote %u cells from skb 0x%p to buffer 0x%p", num_written, skb, buf);
+
+	if (!(buf->free_cells -= num_written)) {
+		list_add_tail (&buf->list, &instance->filled_buffers);
+		instance->current_buffer = NULL;
+		dbg ("queued filled buffer");
+	}
+
+	dbg ("buffer contains %d cells, %d left", UDSL_SND_BUFFER_SIZE - buf->free_cells, buf->free_cells);
+
+	if (!UDSL_SKB (skb)->num_cells) {
+		struct atm_vcc *vcc = UDSL_SKB (skb)->atm_data.vcc;
+
+		dbg ("discarding empty skb");
+		if (vcc->pop)
+			vcc->pop (vcc, skb);
+		else
+			kfree_skb (skb);
+		instance->current_skb = NULL;
+
+		if (vcc->stats)
+			atomic_inc (&vcc->stats->tx);
+	}
+
+	goto made_progress;
+}
+
+static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vcc *vcc)
+{
+	unsigned long flags;
+	struct sk_buff *skb, *n;
+
+	dbg ("udsl_cancel_send entered");
+	spin_lock_irqsave (&instance->sndqueue.lock, flags);
+	for (skb = instance->sndqueue.next, n = skb->next; skb != (struct sk_buff *)&instance->sndqueue; skb = n, n = skb->next)
+		if (UDSL_SKB (skb)->atm_data.vcc == vcc) {
+			dbg ("popping skb 0x%p", skb);
+			__skb_unlink (skb, &instance->sndqueue);
+			if (vcc->pop)
+				vcc->pop (vcc, skb);
+			else
+				kfree_skb (skb);
+		}
+	spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
+
+	tasklet_disable (&instance->send_tasklet);
+	if ((skb = instance->current_skb) && (UDSL_SKB (skb)->atm_data.vcc == vcc)) {
+		dbg ("popping current skb (0x%p)", skb);
+		instance->current_skb = NULL;
+		if (vcc->pop)
+			vcc->pop (vcc, skb);
+		else
+			kfree_skb (skb);
+	}
+	tasklet_enable (&instance->send_tasklet);
+	dbg ("udsl_cancel_send done");
+}
+
+static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	struct udsl_instance_data *instance = vcc->dev->dev_data;
+
+	dbg ("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
+
+	if (!instance || !instance->usb_dev) {
+		dbg ("NULL data!");
+		return -ENODEV;
+	}
+
+	if (!instance->firmware_loaded)
+		return -EAGAIN;
+
+	if (vcc->qos.aal != ATM_AAL5) {
+		dbg ("unsupported ATM type %d!", vcc->qos.aal);
+		return -EINVAL;
+	}
+
+	if (skb->len > ATM_MAX_AAL5_PDU) {
+		dbg ("packet too long (%d vs %d)!", skb->len, ATM_MAX_AAL5_PDU);
+		return -EINVAL;
+	}
+
+	PACKETDEBUG (skb->data, skb->len);
+
+	udsl_groom_skb (vcc, skb);
+	skb_queue_tail (&instance->sndqueue, skb);
+	tasklet_schedule (&instance->send_tasklet);
+
+	return 0;
+}
+
+
+/**********
+**  ATM  **
+**********/
+
+#define ATMSAR_DEF_MTU_AAL0		48
+#define ATMSAR_DEF_MTU_AAL1		47
+#define ATMSAR_DEF_MTU_AAL2		0  /* not supported */
+#define ATMSAR_DEF_MTU_AAL34		0  /* not supported */
+#define ATMSAR_DEF_MTU_AAL5		65535  /* max mtu ..    */
+
+struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type,
+				     ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
+{
+	struct atmsar_vcc_data *new;
+
+	if (!vcc)
+		return NULL;
+
+	new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL);
+
+	if (!new)
+		return NULL;
+
+	memset (new, 0, sizeof (struct atmsar_vcc_data));
+	new->vcc = vcc;
+	new->stats = vcc->stats;
+	new->type = type;
+	new->next = NULL;
+	new->gfc = gfc;
+	new->vp = vpi;
+	new->vc = vci;
+	new->pti = pti;
+
+	switch (type) {
+	case ATM_AAL0:
+		new->mtu = ATMSAR_DEF_MTU_AAL0;
+		break;
+	case ATM_AAL1:
+		new->mtu = ATMSAR_DEF_MTU_AAL1;
+		break;
+	case ATM_AAL2:
+		new->mtu = ATMSAR_DEF_MTU_AAL2;
+		break;
+	case ATM_AAL34:
+		/* not supported */
+		new->mtu = ATMSAR_DEF_MTU_AAL34;
+		break;
+	case ATM_AAL5:
+		new->mtu = ATMSAR_DEF_MTU_AAL5;
+		break;
+	}
+
+	new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT)
+	    | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT)
+	    | ((unsigned long) vci << ATM_HDR_VCI_SHIFT)
+	    | ((unsigned long) pti << ATM_HDR_PTI_SHIFT);
+	new->flags = flags;
+	new->next = NULL;
+	new->reasBuffer = NULL;
+
+	new->next = *list;
+	*list = new;
+
+	dbg ("Allocated new SARLib vcc 0x%p with vp %d vc %d", new, vpi, vci);
+
+	return new;
+}
+
+void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
+{
+	struct atmsar_vcc_data *work;
+
+	if (*list == vcc) {
+		*list = (*list)->next;
+	} else {
+		for (work = *list; work && work->next && (work->next != vcc); work = work->next);
+
+		/* return if not found */
+		if (work->next != vcc)
+			return;
+
+		work->next = work->next->next;
+	}
+
+	if (vcc->reasBuffer) {
+		dev_kfree_skb (vcc->reasBuffer);
+	}
+
+	dbg ("Allocated SARLib vcc 0x%p with vp %d vc %d", vcc, vcc->vp, vcc->vc);
+
+	kfree (vcc);
+}
+
+static void udsl_atm_dev_close (struct atm_dev *dev)
+{
+	struct udsl_instance_data *instance = dev->dev_data;
+
+	if (!instance) {
+		dbg ("udsl_atm_dev_close: NULL instance!");
+		return;
+	}
+
+	dbg ("udsl_atm_dev_close: queue has %u elements", instance->sndqueue.qlen);
+
+	dbg ("udsl_atm_dev_close: killing tasklet");
+	tasklet_kill (&instance->send_tasklet);
+	dbg ("udsl_atm_dev_close: freeing instance");
+	kfree (instance);
+	dev->dev_data = NULL;
+}
+
+static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
+{
+	struct udsl_instance_data *instance = atm_dev->dev_data;
+	int left = *pos;
+
+	if (!instance) {
+		dbg ("NULL instance!");
+		return -ENODEV;
+	}
+
+	if (!left--)
+		return sprintf (page, "%s\n", instance->description);
+
+	if (!left--)
+		return sprintf (page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+				atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2],
+				atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
+
+	if (!left--)
+		return sprintf (page, "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
+				atomic_read (&atm_dev->stats.aal5.tx),
+				atomic_read (&atm_dev->stats.aal5.tx_err),
+				atomic_read (&atm_dev->stats.aal5.rx),
+				atomic_read (&atm_dev->stats.aal5.rx_err),
+				atomic_read (&atm_dev->stats.aal5.rx_drop));
+
+	if (!left--) {
+		switch (atm_dev->signal) {
+		case ATM_PHY_SIG_FOUND:
+			sprintf (page, "Line up");
+			break;
+		case ATM_PHY_SIG_LOST:
+			sprintf (page, "Line down");
+			break;
+		default:
+			sprintf (page, "Line state unknown");
+			break;
+		}
+
+		if (instance->usb_dev) {
+			if (!instance->firmware_loaded)
+				strcat (page, ", no firmware\n");
+			else
+				strcat (page, ", firmware loaded\n");
+		} else
+			strcat (page, ", disconnected\n");
+
+		return strlen (page);
+	}
+
+	return 0;
+}
+
+#define ATMSAR_SET_PTI		0x2L
+
+static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
+{
+	struct udsl_instance_data *instance = vcc->dev->dev_data;
+
+	dbg ("udsl_atm_open called");
+
+	if (!instance || !instance->usb_dev) {
+		dbg ("NULL data!");
+		return -ENODEV;
+	}
+
+	/* at the moment only AAL5 support */
+	if (vcc->qos.aal != ATM_AAL5)
+		return -EINVAL;
+
+	MOD_INC_USE_COUNT;
+
+	vcc->dev_data =
+	    atmsar_open (&(instance->atmsar_vcc_list), vcc, ATM_AAL5, vpi, vci, 0, 0,
+			 ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI);
+	if (!vcc->dev_data) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;	/* this is the only reason atmsar_open can fail... */
+	}
+
+	vcc->vpi = vpi;
+	vcc->vci = vci;
+	set_bit (ATM_VF_ADDR, &vcc->flags);
+	set_bit (ATM_VF_PARTIAL, &vcc->flags);
+	set_bit (ATM_VF_READY, &vcc->flags);
+
+	((struct atmsar_vcc_data *)vcc->dev_data)->mtu = UDSL_MAX_AAL5_MRU;
+
+	if (instance->firmware_loaded)
+		udsl_fire_receivers (instance);
+
+	dbg ("udsl_atm_open successful");
+	return 0;
+}
+
+static void udsl_atm_close (struct atm_vcc *vcc)
+{
+	struct udsl_instance_data *instance = vcc->dev->dev_data;
+
+	dbg ("udsl_atm_close called");
+
+	if (!instance) {
+		dbg ("NULL instance!");
+		return;
+	}
+
+	/* freeing resources */
+	/* cancel all sends on this vcc */
+	udsl_cancel_send (instance, vcc);
+
+	atmsar_close (&(instance->atmsar_vcc_list), vcc->dev_data);
+	vcc->dev_data = NULL;
+	clear_bit (ATM_VF_PARTIAL, &vcc->flags);
+
+	/* freeing address */
+	vcc->vpi = ATM_VPI_UNSPEC;
+	vcc->vci = ATM_VCI_UNSPEC;
+	clear_bit (ATM_VF_ADDR, &vcc->flags);
+
+	MOD_DEC_USE_COUNT;
+
+	dbg ("udsl_atm_close successful");
+	return;
+}
+
+static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
+{
+	switch (cmd) {
+	case ATM_QUERYLOOP:
+		return put_user (ATM_LM_NONE, (int *) arg) ? -EFAULT : 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+
+/**********
+**  USB  **
+**********/
+
+static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data)
+{
+	struct udsl_instance_data *instance = usb_get_intfdata (intf);
+
+	dbg ("udsl_usb_ioctl entered");
+
+	if (!instance) {
+		dbg ("NULL instance!");
+		return -ENODEV;
+	}
+
+	switch (code) {
+	case UDSL_IOCTL_START:
+		instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
+		down (&instance->serialize); /* vs self */
+		if (!instance->firmware_loaded) {
+			usb_set_interface (instance->usb_dev, 1, 1);
+			instance->firmware_loaded = 1;
+		}
+		up (&instance->serialize);
+		udsl_fire_receivers (instance);
+		return 0;
+	case UDSL_IOCTL_STOP:
+		instance->atm_dev->signal = ATM_PHY_SIG_LOST;
+		return 0;
+	default:
+		return -ENOTTY;
+	}
+}
+
+static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int ifnum = intf->altsetting->desc.bInterfaceNumber;
+	struct udsl_instance_data *instance;
+	unsigned char mac_str [13];
+	int i, length;
+	char *buf;
+
+	dbg ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d",
+		dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
+	if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
+	    (dev->descriptor.idVendor != SPEEDTOUCH_VENDORID) ||
+	    (dev->descriptor.idProduct != SPEEDTOUCH_PRODUCTID) || (ifnum != 1))
+		return -ENODEV;
+
+	dbg ("Device Accepted");
+
+	/* instance init */
+	if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
+		dbg ("No memory for Instance data!");
+		return -ENOMEM;
+	}
+
+	memset (instance, 0, sizeof (struct udsl_instance_data));
+
+	init_MUTEX (&instance->serialize);
+
+	instance->usb_dev = dev;
+
+	spin_lock_init (&instance->spare_receivers_lock);
+	INIT_LIST_HEAD (&instance->spare_receivers);
+
+	spin_lock_init (&instance->completed_receivers_lock);
+	INIT_LIST_HEAD (&instance->completed_receivers);
+
+	tasklet_init (&instance->receive_tasklet, udsl_process_receive, (unsigned long) instance);
+
+	skb_queue_head_init (&instance->sndqueue);
+
+	spin_lock_init (&instance->send_lock);
+	INIT_LIST_HEAD (&instance->spare_senders);
+	INIT_LIST_HEAD (&instance->spare_buffers);
+
+	tasklet_init (&instance->send_tasklet, udsl_process_send, (unsigned long) instance);
+	INIT_LIST_HEAD (&instance->filled_buffers);
+
+	/* receive init */
+	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
+		struct udsl_receiver *rcv = &(instance->all_receivers[i]);
+
+		if (!(rcv->skb = dev_alloc_skb (UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE))) {
+			dbg ("No memory for skb %d!", i);
+			goto fail;
+		}
+
+		if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) {
+			dbg ("No memory for receive urb %d!", i);
+			goto fail;
+		}
+
+		rcv->instance = instance;
+
+		list_add (&rcv->list, &instance->spare_receivers);
+
+		dbg ("skb->truesize = %d (asked for %d)", rcv->skb->truesize, UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE);
+	}
+
+	/* send init */
+	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
+		struct udsl_sender *snd = &(instance->all_senders[i]);
+
+		if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) {
+			dbg ("No memory for send urb %d!", i);
+			goto fail;
+		}
+
+		snd->instance = instance;
+
+		list_add (&snd->list, &instance->spare_senders);
+	}
+
+	for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++) {
+		struct udsl_send_buffer *buf = &(instance->all_buffers[i]);
+
+		if (!(buf->base = kmalloc (UDSL_SND_BUFFER_SIZE * ATM_CELL_SIZE, GFP_KERNEL))) {
+			dbg ("No memory for send buffer %d!", i);
+			goto fail;
+		}
+
+		list_add (&buf->list, &instance->spare_buffers);
+	}
+
+	/* atm init */
+	if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) {
+		dbg ("failed to register ATM device!");
+		goto fail;
+	}
+
+	instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
+	instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
+	instance->atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+
+	/* tmp init atm device, set to 128kbit */
+	instance->atm_dev->link_rate = 128 * 1000 / 424;
+
+	/* set MAC address, it is stored in the serial number */
+	memset (instance->atm_dev->esi, 0, sizeof (instance->atm_dev->esi));
+	if (usb_string (dev, dev->descriptor.iSerialNumber, mac_str, sizeof (mac_str)) == 12)
+		for (i = 0; i < 6; i++)
+			instance->atm_dev->esi[i] = (hex2int (mac_str[i * 2]) * 16) + (hex2int (mac_str[i * 2 + 1]));
+
+	/* device description */
+	buf = instance->description;
+	length = sizeof (instance->description);
+
+	if ((i = usb_string (dev, dev->descriptor.iProduct, buf, length)) < 0)
+		goto finish;
+
+	buf += i;
+	length -= i;
+
+	i = snprintf (buf, length, " (");
+	buf += i;
+	length -= i;
+
+	if (length <= 0 || (i = usb_make_path (dev, buf, length)) < 0)
+		goto finish;
+
+	buf += i;
+	length -= i;
+
+	snprintf (buf, length, ")");
+
+finish:
+	/* ready for ATM callbacks */
+	instance->atm_dev->dev_data = instance;
+
+	usb_set_intfdata (intf, instance);
+
+	return 0;
+
+fail:
+	for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
+		kfree (instance->all_buffers[i].base);
+
+	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
+		usb_free_urb (instance->all_senders[i].urb);
+
+	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
+		struct udsl_receiver *rcv = &(instance->all_receivers[i]);
+
+		usb_free_urb (rcv->urb);
+
+		if (rcv->skb)
+			kfree_skb (rcv->skb);
+	}
+
+	kfree (instance);
+
+	return -ENOMEM;
+}
+
+static void udsl_usb_disconnect (struct usb_interface *intf)
+{
+	struct udsl_instance_data *instance = usb_get_intfdata (intf);
+	struct list_head *pos;
+	unsigned long flags;
+	unsigned int count = 0;
+	int result, i;
+
+	dbg ("disconnecting");
+
+	usb_set_intfdata (intf, NULL);
+
+	if (!instance) {
+		dbg ("NULL instance!");
+		return;
+	}
+
+	tasklet_disable (&instance->receive_tasklet);
+
+	/* receive finalize */
+	down (&instance->serialize); /* vs udsl_fire_receivers */
+	/* no need to take the spinlock */
+	list_for_each (pos, &instance->spare_receivers)
+		if (++count > UDSL_NUMBER_RCV_URBS)
+			panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
+	INIT_LIST_HEAD (&instance->spare_receivers);
+	up (&instance->serialize);
+
+	dbg ("udsl_usb_disconnect: flushed %u spare receivers", count);
+
+	count = UDSL_NUMBER_RCV_URBS - count;
+
+	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++)
+		if ((result = usb_unlink_urb (instance->all_receivers[i].urb)) < 0)
+			dbg ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d", i, result);
+
+	/* wait for completion handlers to finish */
+	do {
+		unsigned int completed = 0;
+
+		spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+		list_for_each (pos, &instance->completed_receivers)
+			if (++completed > count)
+				panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
+		spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+
+		dbg ("udsl_usb_disconnect: found %u completed receivers", completed);
+
+		if (completed == count)
+			break;
+
+		yield ();
+	} while (1);
+
+	dbg ("udsl_usb_disconnect: flushing");
+	/* no need to take the spinlock */
+	INIT_LIST_HEAD (&instance->completed_receivers);
+
+	tasklet_enable (&instance->receive_tasklet);
+	tasklet_kill (&instance->receive_tasklet);
+
+	dbg ("udsl_usb_disconnect: freeing receivers");
+	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
+		struct udsl_receiver *rcv = &(instance->all_receivers[i]);
+
+		usb_free_urb (rcv->urb);
+		kfree_skb (rcv->skb);
+	}
+
+	/* send finalize */
+	tasklet_disable (&instance->send_tasklet);
+
+	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
+		if ((result = usb_unlink_urb (instance->all_senders[i].urb)) < 0)
+			dbg ("udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d", i, result);
+
+	/* wait for completion handlers to finish */
+	do {
+		count = 0;
+		spin_lock_irqsave (&instance->send_lock, flags);
+		list_for_each (pos, &instance->spare_senders)
+			if (++count > UDSL_NUMBER_SND_URBS)
+				panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
+		spin_unlock_irqrestore (&instance->send_lock, flags);
+
+		dbg ("udsl_usb_disconnect: found %u spare senders", count);
+
+		if (count == UDSL_NUMBER_SND_URBS)
+			break;
+
+		yield ();
+	} while (1);
+
+	dbg ("udsl_usb_disconnect: flushing");
+	/* no need to take the spinlock */
+	INIT_LIST_HEAD (&instance->spare_senders);
+	INIT_LIST_HEAD (&instance->spare_buffers);
+	instance->current_buffer = NULL;
+
+	tasklet_enable (&instance->send_tasklet);
+
+	dbg ("udsl_usb_disconnect: freeing senders");
+	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
+		usb_free_urb (instance->all_senders[i].urb);
+
+	dbg ("udsl_usb_disconnect: freeing buffers");
+	for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
+		kfree (instance->all_buffers[i].base);
+
+	instance->usb_dev = NULL;
+
+	/* atm finalize */
+	shutdown_atm_dev (instance->atm_dev); /* frees instance */
+}
+
+
+/***********
+**  init  **
+***********/
+
+static int __init udsl_usb_init (void)
+{
+	struct sk_buff *skb; /* dummy for sizeof */
+
+	dbg ("udsl_usb_init: driver version " DRIVER_VERSION);
+
+	if (sizeof (struct udsl_control) > sizeof (skb->cb)) {
+		printk (KERN_ERR __FILE__ ": unusable with this kernel!\n");
+		return -EIO;
+	}
+
+	return usb_register (&udsl_usb_driver);
+}
+
+static void __exit udsl_usb_cleanup (void)
+{
+	dbg ("udsl_usb_cleanup");
+
+	usb_deregister (&udsl_usb_driver);
+}
+
+module_init (udsl_usb_init);
+module_exit (udsl_usb_cleanup);
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE ("GPL");
+
+
+/************
+**  debug  **
+************/
+
+#ifdef DEBUG_PACKET
+static int udsl_print_packet (const unsigned char *data, int len)
+{
+	unsigned char buffer [256];
+	int i = 0, j = 0;
+
+	for (i = 0; i < len;) {
+		buffer[0] = '\0';
+		sprintf (buffer, "%.3d :", i);
+		for (j = 0; (j < 16) && (i < len); j++, i++) {
+			sprintf (buffer, "%s %2.2x", buffer, data[i]);
+		}
+		dbg ("%s", buffer);
+	}
+	return i;
+}
+#endif
diff -urN linux-2.5.65-bk1/drivers/usb/misc/speedtouch.c linux-2.5.65-bk2/drivers/usb/misc/speedtouch.c
--- linux-2.5.65-bk1/drivers/usb/misc/speedtouch.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/drivers/usb/misc/speedtouch.c	Wed Dec 31 16:00:00 1969
@@ -1,1241 +0,0 @@
-/******************************************************************************
- *  speedtouch.c  --  Alcatel SpeedTouch USB xDSL modem driver.
- *
- *  Copyright (C) 2001, Alcatel
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- *  more details.
- *
- *  You should have received a copy of the GNU General Public License along with
- *  this program; if not, write to the Free Software Foundation, Inc., 59
- *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- ******************************************************************************/
-
-/*
- *  Written by Johan Verrept (Johan.Verrept@advalvas.be)
- *
- *  1.5A:	- Version for inclusion in 2.5 series kernel
- *		- Modifications by Richard Purdie (rpurdie@rpsys.net)
- *		- made compatible with kernel 2.5.6 onwards by changing
- *		udsl_usb_send_data_context->urb to a pointer and adding code
- *		to alloc and free it
- *		- remove_wait_queue() added to udsl_atm_processqueue_thread()
- *
- *  1.5:	- fixed memory leak when atmsar_decode_aal5 returned NULL.
- *		(reported by stephen.robinson@zen.co.uk)
- *
- *  1.4:	- changed the spin_lock() under interrupt to spin_lock_irqsave()
- *		- unlink all active send urbs of a vcc that is being closed.
- *
- *  1.3.1:	- added the version number
- *
- *  1.3:	- Added multiple send urb support
- *		- fixed memory leak and vcc->tx_inuse starvation bug
- *		  when not enough memory left in vcc.
- *
- *  1.2:	- Fixed race condition in udsl_usb_send_data()
- *  1.1:	- Turned off packet debugging
- *
- */
-
-#include <asm/semaphore.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/crc32.h>
-#include "atmsar.h"
-
-/*
-#define DEBUG 1
-#define DEBUG_PACKET 1
-*/
-
-#include <linux/usb.h>
-
-
-#ifdef DEBUG_PACKET
-static int udsl_print_packet (const unsigned char *data, int len);
-#define PACKETDEBUG(arg...) udsl_print_packet (arg)
-#else
-#define PACKETDEBUG(arg...)
-#endif
-
-#define DRIVER_AUTHOR	"Johan Verrept, Johan.Verrept@advalvas.be"
-#define DRIVER_DESC	"Driver for the Alcatel SpeedTouch USB ADSL modem"
-#define DRIVER_VERSION	"1.5A"
-
-#define SPEEDTOUCH_VENDORID		0x06b9
-#define SPEEDTOUCH_PRODUCTID		0x4061
-
-#define UDSL_NUMBER_RCV_URBS		1
-#define UDSL_NUMBER_SND_URBS		1
-#define UDSL_NUMBER_SND_BUFS		(2*UDSL_NUMBER_SND_URBS)
-#define UDSL_RCV_BUFFER_SIZE		(1*64) /* ATM cells */
-#define UDSL_SND_BUFFER_SIZE		(1*64) /* ATM cells */
-/* max should be (1500 IP mtu + 2 ppp bytes + 32 * 5 cellheader overhead) for
- * PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */
-#define UDSL_MAX_AAL5_MRU		2048
-
-#define UDSL_IOCTL_START		1
-#define UDSL_IOCTL_STOP			2
-
-/* endpoint declarations */
-
-#define UDSL_ENDPOINT_DATA_OUT		0x07
-#define UDSL_ENDPOINT_DATA_IN		0x87
-
-#define hex2int(c) ( (c >= '0')&&(c <= '9') ?  (c - '0') : ((c & 0xf)+9) )
-
-/* usb_device_id struct */
-
-static struct usb_device_id udsl_usb_ids [] = {
-	{ USB_DEVICE (SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID) },
-	{ }			/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, udsl_usb_ids);
-
-/* context declarations */
-
-struct udsl_receiver {
-	struct list_head list;
-	struct sk_buff *skb;
-	struct urb *urb;
-	struct udsl_instance_data *instance;
-};
-
-struct udsl_send_buffer {
-	struct list_head list;
-	unsigned char *base;
-	unsigned char *free_start;
-	unsigned int free_cells;
-};
-
-struct udsl_sender {
-	struct list_head list;
-	struct udsl_send_buffer *buffer;
-	struct urb *urb;
-	struct udsl_instance_data *instance;
-};
-
-struct udsl_control {
-	struct atm_skb_data atm_data;
-	unsigned int num_cells;
-	unsigned int num_entire;
-	unsigned char cell_header [ATM_CELL_HEADER];
-	unsigned int pdu_padding;
-	unsigned char aal5_trailer [ATM_AAL5_TRAILER];
-};
-
-#define UDSL_SKB(x)		((struct udsl_control *)(x)->cb)
-
-/*
- * UDSL main driver data
- */
-
-struct udsl_instance_data {
-	struct semaphore serialize;
-
-	/* usb device part */
-	struct usb_device *usb_dev;
-	char description [64];
-	int firmware_loaded;
-
-	/* atm device part */
-	struct atm_dev *atm_dev;
-	struct atmsar_vcc_data *atmsar_vcc_list;
-
-	/* receiving */
-	struct udsl_receiver all_receivers [UDSL_NUMBER_RCV_URBS];
-
-	spinlock_t spare_receivers_lock;
-	struct list_head spare_receivers;
-
-	spinlock_t completed_receivers_lock;
-	struct list_head completed_receivers;
-
-	struct tasklet_struct receive_tasklet;
-
-	/* sending */
-	struct udsl_sender all_senders [UDSL_NUMBER_SND_URBS];
-	struct udsl_send_buffer all_buffers [UDSL_NUMBER_SND_BUFS];
-
-	struct sk_buff_head sndqueue;
-
-	spinlock_t send_lock;
-	struct list_head spare_senders;
-	struct list_head spare_buffers;
-
-	struct tasklet_struct send_tasklet;
-	struct sk_buff *current_skb;			/* being emptied */
-	struct udsl_send_buffer *current_buffer;	/* being filled */
-	struct list_head filled_buffers;
-};
-
-static const char udsl_driver_name [] = "speedtch";
-
-/*
- * atm driver prototypes and structures
- */
-
-static void udsl_atm_dev_close (struct atm_dev *dev);
-static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci);
-static void udsl_atm_close (struct atm_vcc *vcc);
-static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg);
-static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb);
-static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page);
-
-static struct atmdev_ops udsl_atm_devops = {
-	.dev_close =	udsl_atm_dev_close,
-	.open =		udsl_atm_open,
-	.close =	udsl_atm_close,
-	.ioctl =	udsl_atm_ioctl,
-	.send =		udsl_atm_send,
-	.proc_read =	udsl_atm_proc_read,
-};
-
-/*
- * usb driver prototypes and structures
- */
-static int udsl_usb_probe (struct usb_interface *intf,
-			   const struct usb_device_id *id);
-static void udsl_usb_disconnect (struct usb_interface *intf);
-static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data);
-
-static struct usb_driver udsl_usb_driver = {
-	.name =		udsl_driver_name,
-	.probe =	udsl_usb_probe,
-	.disconnect =	udsl_usb_disconnect,
-	.ioctl =	udsl_usb_ioctl,
-	.id_table =	udsl_usb_ids,
-};
-
-
-/*************
-**  encode  **
-*************/
-
-static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb) {
-	struct udsl_control *ctrl = UDSL_SKB (skb);
-	unsigned int i, zero_padding;
-	unsigned char zero = 0;
-	u32 crc;
-
-	ctrl->atm_data.vcc = vcc;
-	ctrl->cell_header [0] = vcc->vpi >> 4;
-	ctrl->cell_header [1] = (vcc->vpi << 4) | (vcc->vci >> 12);
-	ctrl->cell_header [2] = vcc->vci >> 4;
-	ctrl->cell_header [3] = vcc->vci << 4;
-	ctrl->cell_header [4] = 0xec;
-
-	ctrl->num_cells = (skb->len + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD;
-	ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
-
-	zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER;
-
-	if (ctrl->num_entire + 1 < ctrl->num_cells)
-		ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
-	else
-		ctrl->pdu_padding = zero_padding;
-
-	ctrl->aal5_trailer [0] = 0; /* UU = 0 */
-	ctrl->aal5_trailer [1] = 0; /* CPI = 0 */
-	ctrl->aal5_trailer [2] = skb->len >> 8;
-	ctrl->aal5_trailer [3] = skb->len;
-
-	crc = crc32_be (~0, skb->data, skb->len);
-	for (i = 0; i < zero_padding; i++)
-		crc = crc32_be (crc, &zero, 1);
-	crc = crc32_be (crc, ctrl->aal5_trailer, 4);
-	crc = ~crc;
-
-	ctrl->aal5_trailer [4] = crc >> 24;
-	ctrl->aal5_trailer [5] = crc >> 16;
-	ctrl->aal5_trailer [6] = crc >> 8;
-	ctrl->aal5_trailer [7] = crc;
-}
-
-unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb, unsigned char **target_p) {
-	struct udsl_control *ctrl = UDSL_SKB (skb);
-	unsigned char *target = *target_p;
-	unsigned int nc, ne, i;
-
-	dbg ("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding);
-
-	nc = ctrl->num_cells;
-	ne = min (howmany, ctrl->num_entire);
-
-	for (i = 0; i < ne; i++) {
-		memcpy (target, ctrl->cell_header, ATM_CELL_HEADER);
-		target += ATM_CELL_HEADER;
-		memcpy (target, skb->data, ATM_CELL_PAYLOAD);
-		target += ATM_CELL_PAYLOAD;
-		__skb_pull (skb, ATM_CELL_PAYLOAD);
-	}
-
-	ctrl->num_entire -= ne;
-
-	if (!(ctrl->num_cells -= ne) || !(howmany -= ne))
-		goto out;
-
-	memcpy (target, ctrl->cell_header, ATM_CELL_HEADER);
-	target += ATM_CELL_HEADER;
-	memcpy (target, skb->data, skb->len);
-	target += skb->len;
-	__skb_pull (skb, skb->len);
-	memset (target, 0, ctrl->pdu_padding);
-	target += ctrl->pdu_padding;
-
-	if (--ctrl->num_cells) {
-		if (!--howmany) {
-			ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
-			goto out;
-		}
-
-		memcpy (target, ctrl->cell_header, ATM_CELL_HEADER);
-		target += ATM_CELL_HEADER;
-		memset (target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
-		target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
-
-		if (--ctrl->num_cells)
-			BUG();
-	}
-
-	memcpy (target, ctrl->aal5_trailer, ATM_AAL5_TRAILER);
-	target += ATM_AAL5_TRAILER;
-	/* set pti bit in last cell */
-	*(target + 3 - ATM_CELL_SIZE) |= 0x2;
-
-out:
-	*target_p = target;
-	return nc - ctrl->num_cells;
-}
-
-
-/**************
-**  receive  **
-**************/
-
-static void udsl_complete_receive (struct urb *urb, struct pt_regs *regs)
-{
-	struct udsl_instance_data *instance;
-	struct udsl_receiver *rcv;
-	unsigned long flags;
-
-	if (!urb || !(rcv = urb->context) || !(instance = rcv->instance)) {
-		dbg ("udsl_complete_receive: bad urb!");
-		return;
-	}
-
-	dbg ("udsl_complete_receive entered (urb 0x%p, status %d)", urb, urb->status);
-
-	/* may not be in_interrupt() */
-	spin_lock_irqsave (&instance->completed_receivers_lock, flags);
-	list_add_tail (&rcv->list, &instance->completed_receivers);
-	tasklet_schedule (&instance->receive_tasklet);
-	spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
-}
-
-static void udsl_process_receive (unsigned long data)
-{
-	struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
-	struct udsl_receiver *rcv;
-	unsigned long flags;
-	unsigned char *data_start;
-	struct sk_buff *skb;
-	struct urb *urb;
-	struct atmsar_vcc_data *atmsar_vcc = NULL;
-	struct sk_buff *new = NULL, *tmp = NULL;
-	int err;
-
-	dbg ("udsl_process_receive entered");
-
-	spin_lock_irqsave (&instance->completed_receivers_lock, flags);
-	while (!list_empty (&instance->completed_receivers)) {
-		rcv = list_entry (instance->completed_receivers.next, struct udsl_receiver, list);
-		list_del (&rcv->list);
-		spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
-
-		urb = rcv->urb;
-		dbg ("udsl_process_receive: got packet %p with length %d and status %d", urb, urb->actual_length, urb->status);
-
-		switch (urb->status) {
-		case 0:
-			dbg ("udsl_process_receive: processing urb with rcv %p, urb %p, skb %p", rcv, urb, rcv->skb);
-
-			/* update the skb structure */
-			skb = rcv->skb;
-			skb_trim (skb, 0);
-			skb_put (skb, urb->actual_length);
-			data_start = skb->data;
-
-			dbg ("skb->len = %d", skb->len);
-			PACKETDEBUG (skb->data, skb->len);
-
-			while ((new =
-				atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
-						       &atmsar_vcc)) != NULL) {
-				dbg ("(after cell processing)skb->len = %d", new->len);
-
-				switch (atmsar_vcc->type) {
-				case ATMSAR_TYPE_AAL5:
-					tmp = new;
-					new = atmsar_decode_aal5 (atmsar_vcc, new);
-
-					/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
-					if (new) {
-						dbg ("(after aal5 decap) skb->len = %d", new->len);
-						if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
-							PACKETDEBUG (new->data, new->len);
-							atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
-						} else {
-							dbg
-							    ("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d",
-							     atomic_read (&atmsar_vcc->vcc->rx_inuse),
-							     atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
-							dev_kfree_skb (new);
-						}
-					} else {
-						dbg ("atmsar_decode_aal5 returned NULL!");
-						dev_kfree_skb (tmp);
-					}
-					break;
-				default:
-					/* not supported. we delete the skb. */
-					printk (KERN_INFO
-						"SpeedTouch USB: illegal vcc type. Dropping packet.\n");
-					dev_kfree_skb (new);
-					break;
-				}
-			}
-
-			/* restore skb */
-			skb_push (skb, skb->data - data_start);
-
-			usb_fill_bulk_urb (urb,
-					   instance->usb_dev,
-					   usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
-					   (unsigned char *) rcv->skb->data,
-					   UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE,
-					   udsl_complete_receive,
-					   rcv);
-			if (!(err = usb_submit_urb (urb, GFP_ATOMIC)))
-				break;
-			dbg ("udsl_process_receive: submission failed (%d)", err);
-			/* fall through */
-		default: /* error or urb unlinked */
-			dbg ("udsl_process_receive: adding to spare_receivers");
-			spin_lock_irqsave (&instance->spare_receivers_lock, flags);
-			list_add (&rcv->list, &instance->spare_receivers);
-			spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
-			break;
-		} /* switch */
-
-		spin_lock_irqsave (&instance->completed_receivers_lock, flags);
-	} /* while */
-	spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
-	dbg ("udsl_process_receive successful");
-}
-
-static void udsl_fire_receivers (struct udsl_instance_data *instance)
-{
-	struct list_head receivers, *pos, *n;
-	unsigned long flags;
-
-	INIT_LIST_HEAD (&receivers);
-
-	down (&instance->serialize);
-
-	spin_lock_irqsave (&instance->spare_receivers_lock, flags);
-	list_splice_init (&instance->spare_receivers, &receivers);
-	spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
-
-	list_for_each_safe (pos, n, &receivers) {
-		struct udsl_receiver *rcv = list_entry (pos, struct udsl_receiver, list);
-
-		dbg ("udsl_fire_receivers: firing urb %p", rcv->urb);
-
-		usb_fill_bulk_urb (rcv->urb,
-				   instance->usb_dev,
-				   usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
-				   (unsigned char *) rcv->skb->data,
-				   UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE,
-				   udsl_complete_receive,
-				   rcv);
-
-		if (usb_submit_urb (rcv->urb, GFP_KERNEL) < 0) {
-			dbg ("udsl_fire_receivers: submit failed!");
-			spin_lock_irqsave (&instance->spare_receivers_lock, flags);
-			list_move (pos, &instance->spare_receivers);
-			spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
-		}
-	}
-
-	up (&instance->serialize);
-}
-
-
-/***********
-**  send  **
-***********/
-
-static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
-{
-	struct udsl_instance_data *instance;
-	struct udsl_sender *snd;
-	unsigned long flags;
-
-	if (!urb || !(snd = urb->context) || !(instance = snd->instance)) {
-		dbg ("udsl_complete_send: bad urb!");
-		return;
-	}
-
-	dbg ("udsl_complete_send entered (urb 0x%p, status %d)", urb, urb->status);
-
-	/* may not be in_interrupt() */
-	spin_lock_irqsave (&instance->send_lock, flags);
-	list_add (&snd->list, &instance->spare_senders);
-	list_add (&snd->buffer->list, &instance->spare_buffers);
-	tasklet_schedule (&instance->send_tasklet);
-	spin_unlock_irqrestore (&instance->send_lock, flags);
-}
-
-static void udsl_process_send (unsigned long data)
-{
-	struct udsl_send_buffer *buf;
-	int err;
-	unsigned long flags;
-	struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
-	unsigned int num_written;
-	struct sk_buff *skb;
-	struct udsl_sender *snd;
-
-	dbg ("udsl_process_send entered");
-
-made_progress:
-	spin_lock_irqsave (&instance->send_lock, flags);
-	while (!list_empty (&instance->spare_senders)) {
-		if (!list_empty (&instance->filled_buffers)) {
-			buf = list_entry (instance->filled_buffers.next, struct udsl_send_buffer, list);
-			list_del (&buf->list);
-			dbg ("sending filled buffer (0x%p)", buf);
-		} else if ((buf = instance->current_buffer)) {
-			instance->current_buffer = NULL;
-			dbg ("sending current buffer (0x%p)", buf);
-		} else /* all buffers empty */
-			break;
-
-		snd = list_entry (instance->spare_senders.next, struct udsl_sender, list);
-		list_del (&snd->list);
-		spin_unlock_irqrestore (&instance->send_lock, flags);
-
-		snd->buffer = buf;
-	        usb_fill_bulk_urb (snd->urb,
-				   instance->usb_dev,
-				   usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
-				   buf->base,
-				   (UDSL_SND_BUFFER_SIZE - buf->free_cells) * ATM_CELL_SIZE,
-				   udsl_complete_send,
-				   snd);
-
-		dbg ("submitting urb 0x%p, contains %d cells", snd->urb, UDSL_SND_BUFFER_SIZE - buf->free_cells);
-
-		if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) {
-			dbg ("submission failed (%d)!", err);
-			spin_lock_irqsave (&instance->send_lock, flags);
-			list_add (&snd->list, &instance->spare_senders);
-			spin_unlock_irqrestore (&instance->send_lock, flags);
-			list_add (&buf->list, &instance->filled_buffers);
-			return;
-		}
-
-		spin_lock_irqsave (&instance->send_lock, flags);
-	} /* while */
-	spin_unlock_irqrestore (&instance->send_lock, flags);
-
-	if (!instance->current_skb && !(instance->current_skb = skb_dequeue (&instance->sndqueue))) {
-		dbg ("done - no more skbs");
-		return;
-	}
-
-	skb = instance->current_skb;
-
-	if (!(buf = instance->current_buffer)) {
-		spin_lock_irqsave (&instance->send_lock, flags);
-		if (list_empty (&instance->spare_buffers)) {
-			instance->current_buffer = NULL;
-			spin_unlock_irqrestore (&instance->send_lock, flags);
-			dbg ("done - no more buffers");
-			return;
-		}
-		buf = list_entry (instance->spare_buffers.next, struct udsl_send_buffer, list);
-		list_del (&buf->list);
-		spin_unlock_irqrestore (&instance->send_lock, flags);
-
-		buf->free_start = buf->base;
-		buf->free_cells = UDSL_SND_BUFFER_SIZE;
-
-		instance->current_buffer = buf;
-	}
-
-	num_written = udsl_write_cells (buf->free_cells, skb, &buf->free_start);
-
-	dbg ("wrote %u cells from skb 0x%p to buffer 0x%p", num_written, skb, buf);
-
-	if (!(buf->free_cells -= num_written)) {
-		list_add_tail (&buf->list, &instance->filled_buffers);
-		instance->current_buffer = NULL;
-		dbg ("queued filled buffer");
-	}
-
-	dbg ("buffer contains %d cells, %d left", UDSL_SND_BUFFER_SIZE - buf->free_cells, buf->free_cells);
-
-	if (!UDSL_SKB (skb)->num_cells) {
-		struct atm_vcc *vcc = UDSL_SKB (skb)->atm_data.vcc;
-
-		dbg ("discarding empty skb");
-		if (vcc->pop)
-			vcc->pop (vcc, skb);
-		else
-			kfree_skb (skb);
-		instance->current_skb = NULL;
-
-		if (vcc->stats)
-			atomic_inc (&vcc->stats->tx);
-	}
-
-	goto made_progress;
-}
-
-static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vcc *vcc)
-{
-	unsigned long flags;
-	struct sk_buff *skb, *n;
-
-	dbg ("udsl_cancel_send entered");
-	spin_lock_irqsave (&instance->sndqueue.lock, flags);
-	for (skb = instance->sndqueue.next, n = skb->next; skb != (struct sk_buff *)&instance->sndqueue; skb = n, n = skb->next)
-		if (UDSL_SKB (skb)->atm_data.vcc == vcc) {
-			dbg ("popping skb 0x%p", skb);
-			__skb_unlink (skb, &instance->sndqueue);
-			if (vcc->pop)
-				vcc->pop (vcc, skb);
-			else
-				kfree_skb (skb);
-		}
-	spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
-
-	tasklet_disable (&instance->send_tasklet);
-	if ((skb = instance->current_skb) && (UDSL_SKB (skb)->atm_data.vcc == vcc)) {
-		dbg ("popping current skb (0x%p)", skb);
-		instance->current_skb = NULL;
-		if (vcc->pop)
-			vcc->pop (vcc, skb);
-		else
-			kfree_skb (skb);
-	}
-	tasklet_enable (&instance->send_tasklet);
-	dbg ("udsl_cancel_send done");
-}
-
-static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
-{
-	struct udsl_instance_data *instance = vcc->dev->dev_data;
-
-	dbg ("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
-
-	if (!instance || !instance->usb_dev) {
-		dbg ("NULL data!");
-		return -ENODEV;
-	}
-
-	if (!instance->firmware_loaded)
-		return -EAGAIN;
-
-	if (vcc->qos.aal != ATM_AAL5) {
-		dbg ("unsupported ATM type %d!", vcc->qos.aal);
-		return -EINVAL;
-	}
-
-	if (skb->len > ATM_MAX_AAL5_PDU) {
-		dbg ("packet too long (%d vs %d)!", skb->len, ATM_MAX_AAL5_PDU);
-		return -EINVAL;
-	}
-
-	PACKETDEBUG (skb->data, skb->len);
-
-	udsl_groom_skb (vcc, skb);
-	skb_queue_tail (&instance->sndqueue, skb);
-	tasklet_schedule (&instance->send_tasklet);
-
-	return 0;
-}
-
-
-/************
-**   ATM   **
-************/
-
-/***************************************************************************
-*
-* init functions
-*
-****************************************************************************/
-
-static void udsl_atm_dev_close (struct atm_dev *dev)
-{
-	struct udsl_instance_data *instance = dev->dev_data;
-
-	if (!instance) {
-		dbg ("udsl_atm_dev_close: NULL instance!");
-		return;
-	}
-
-	dbg ("udsl_atm_dev_close: queue has %u elements", instance->sndqueue.qlen);
-
-	dbg ("udsl_atm_dev_close: killing tasklet");
-	tasklet_kill (&instance->send_tasklet);
-	dbg ("udsl_atm_dev_close: freeing instance");
-	kfree (instance);
-	dev->dev_data = NULL;
-}
-
-
-/***************************************************************************
-*
-* ATM helper functions
-*
-****************************************************************************/
-
-static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
-{
-	struct udsl_instance_data *instance = atm_dev->dev_data;
-	int left = *pos;
-
-	if (!instance) {
-		dbg ("NULL instance!");
-		return -ENODEV;
-	}
-
-	if (!left--)
-		return sprintf (page, "%s\n", instance->description);
-
-	if (!left--)
-		return sprintf (page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
-				atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2],
-				atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
-
-	if (!left--)
-		return sprintf (page, "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
-				atomic_read (&atm_dev->stats.aal5.tx),
-				atomic_read (&atm_dev->stats.aal5.tx_err),
-				atomic_read (&atm_dev->stats.aal5.rx),
-				atomic_read (&atm_dev->stats.aal5.rx_err),
-				atomic_read (&atm_dev->stats.aal5.rx_drop));
-
-	if (!left--) {
-		switch (atm_dev->signal) {
-		case ATM_PHY_SIG_FOUND:
-			sprintf (page, "Line up");
-			break;
-		case ATM_PHY_SIG_LOST:
-			sprintf (page, "Line down");
-			break;
-		default:
-			sprintf (page, "Line state unknown");
-			break;
-		}
-
-		if (instance->usb_dev) {
-			if (!instance->firmware_loaded)
-				strcat (page, ", no firmware\n");
-			else
-				strcat (page, ", firmware loaded\n");
-		} else
-			strcat (page, ", disconnected\n");
-
-		return strlen (page);
-	}
-
-	return 0;
-}
-
-
-/***************************************************************************
-*
-* SAR driver entries
-*
-****************************************************************************/
-
-static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
-{
-	struct udsl_instance_data *instance = vcc->dev->dev_data;
-
-	dbg ("udsl_atm_open called");
-
-	if (!instance || !instance->usb_dev) {
-		dbg ("NULL data!");
-		return -ENODEV;
-	}
-
-	/* at the moment only AAL5 support */
-	if (vcc->qos.aal != ATM_AAL5)
-		return -EINVAL;
-
-	MOD_INC_USE_COUNT;
-
-	vcc->dev_data =
-	    atmsar_open (&(instance->atmsar_vcc_list), vcc, ATMSAR_TYPE_AAL5, vpi, vci, 0, 0,
-			 ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI);
-	if (!vcc->dev_data) {
-		MOD_DEC_USE_COUNT;
-		return -ENOMEM;	/* this is the only reason atmsar_open can fail... */
-	}
-
-	vcc->vpi = vpi;
-	vcc->vci = vci;
-	set_bit (ATM_VF_ADDR, &vcc->flags);
-	set_bit (ATM_VF_PARTIAL, &vcc->flags);
-	set_bit (ATM_VF_READY, &vcc->flags);
-
-	((struct atmsar_vcc_data *)vcc->dev_data)->mtu = UDSL_MAX_AAL5_MRU;
-
-	if (instance->firmware_loaded)
-		udsl_fire_receivers (instance);
-
-	dbg ("udsl_atm_open successful");
-	return 0;
-}
-
-static void udsl_atm_close (struct atm_vcc *vcc)
-{
-	struct udsl_instance_data *instance = vcc->dev->dev_data;
-
-	dbg ("udsl_atm_close called");
-
-	if (!instance) {
-		dbg ("NULL instance!");
-		return;
-	}
-
-	/* freeing resources */
-	/* cancel all sends on this vcc */
-	udsl_cancel_send (instance, vcc);
-
-	atmsar_close (&(instance->atmsar_vcc_list), vcc->dev_data);
-	vcc->dev_data = NULL;
-	clear_bit (ATM_VF_PARTIAL, &vcc->flags);
-
-	/* freeing address */
-	vcc->vpi = ATM_VPI_UNSPEC;
-	vcc->vci = ATM_VCI_UNSPEC;
-	clear_bit (ATM_VF_ADDR, &vcc->flags);
-
-	MOD_DEC_USE_COUNT;
-
-	dbg ("udsl_atm_close successful");
-	return;
-}
-
-static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
-{
-	switch (cmd) {
-	case ATM_QUERYLOOP:
-		return put_user (ATM_LM_NONE, (int *) arg) ? -EFAULT : 0;
-	default:
-		return -ENOIOCTLCMD;
-	}
-}
-
-
-/************
-**   USB   **
-************/
-
-static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data)
-{
-	struct udsl_instance_data *instance = usb_get_intfdata (intf);
-
-	dbg ("udsl_usb_ioctl entered");
-
-	if (!instance) {
-		dbg ("NULL instance!");
-		return -ENODEV;
-	}
-
-	switch (code) {
-	case UDSL_IOCTL_START:
-		instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
-		down (&instance->serialize); /* vs self */
-		if (!instance->firmware_loaded) {
-			usb_set_interface (instance->usb_dev, 1, 1);
-			instance->firmware_loaded = 1;
-		}
-		up (&instance->serialize);
-		udsl_fire_receivers (instance);
-		return 0;
-	case UDSL_IOCTL_STOP:
-		instance->atm_dev->signal = ATM_PHY_SIG_LOST;
-		return 0;
-	default:
-		return -ENOTTY;
-	}
-}
-
-static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev(intf);
-	int ifnum = intf->altsetting->desc.bInterfaceNumber;
-	struct udsl_instance_data *instance;
-	unsigned char mac_str [13];
-	int i, length;
-	char *buf;
-
-	dbg ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d",
-		dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
-
-	if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
-	    (dev->descriptor.idVendor != SPEEDTOUCH_VENDORID) ||
-	    (dev->descriptor.idProduct != SPEEDTOUCH_PRODUCTID) || (ifnum != 1))
-		return -ENODEV;
-
-	dbg ("Device Accepted");
-
-	/* instance init */
-	if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
-		dbg ("No memory for Instance data!");
-		return -ENOMEM;
-	}
-
-	memset (instance, 0, sizeof (struct udsl_instance_data));
-
-	init_MUTEX (&instance->serialize);
-
-	instance->usb_dev = dev;
-
-	spin_lock_init (&instance->spare_receivers_lock);
-	INIT_LIST_HEAD (&instance->spare_receivers);
-
-	spin_lock_init (&instance->completed_receivers_lock);
-	INIT_LIST_HEAD (&instance->completed_receivers);
-
-	tasklet_init (&instance->receive_tasklet, udsl_process_receive, (unsigned long) instance);
-
-	skb_queue_head_init (&instance->sndqueue);
-
-	spin_lock_init (&instance->send_lock);
-	INIT_LIST_HEAD (&instance->spare_senders);
-	INIT_LIST_HEAD (&instance->spare_buffers);
-
-	tasklet_init (&instance->send_tasklet, udsl_process_send, (unsigned long) instance);
-	INIT_LIST_HEAD (&instance->filled_buffers);
-
-	/* receive init */
-	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
-		struct udsl_receiver *rcv = &(instance->all_receivers[i]);
-
-		if (!(rcv->skb = dev_alloc_skb (UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE))) {
-			dbg ("No memory for skb %d!", i);
-			goto fail;
-		}
-
-		if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) {
-			dbg ("No memory for receive urb %d!", i);
-			goto fail;
-		}
-
-		rcv->instance = instance;
-
-		list_add (&rcv->list, &instance->spare_receivers);
-
-		dbg ("skb->truesize = %d (asked for %d)", rcv->skb->truesize, UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE);
-	}
-
-	/* send init */
-	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
-		struct udsl_sender *snd = &(instance->all_senders[i]);
-
-		if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) {
-			dbg ("No memory for send urb %d!", i);
-			goto fail;
-		}
-
-		snd->instance = instance;
-
-		list_add (&snd->list, &instance->spare_senders);
-	}
-
-	for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++) {
-		struct udsl_send_buffer *buf = &(instance->all_buffers[i]);
-
-		if (!(buf->base = kmalloc (UDSL_SND_BUFFER_SIZE * ATM_CELL_SIZE, GFP_KERNEL))) {
-			dbg ("No memory for send buffer %d!", i);
-			goto fail;
-		}
-
-		list_add (&buf->list, &instance->spare_buffers);
-	}
-
-	/* atm init */
-	if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) {
-		dbg ("failed to register ATM device!");
-		goto fail;
-	}
-
-	instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
-	instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
-	instance->atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-
-	/* tmp init atm device, set to 128kbit */
-	instance->atm_dev->link_rate = 128 * 1000 / 424;
-
-	/* set MAC address, it is stored in the serial number */
-	memset (instance->atm_dev->esi, 0, sizeof (instance->atm_dev->esi));
-	if (usb_string (dev, dev->descriptor.iSerialNumber, mac_str, sizeof (mac_str)) == 12)
-		for (i = 0; i < 6; i++)
-			instance->atm_dev->esi[i] = (hex2int (mac_str[i * 2]) * 16) + (hex2int (mac_str[i * 2 + 1]));
-
-	/* device description */
-	buf = instance->description;
-	length = sizeof (instance->description);
-
-	if ((i = usb_string (dev, dev->descriptor.iProduct, buf, length)) < 0)
-		goto finish;
-
-	buf += i;
-	length -= i;
-
-	i = snprintf (buf, length, " (");
-	buf += i;
-	length -= i;
-
-	if (length <= 0 || (i = usb_make_path (dev, buf, length)) < 0)
-		goto finish;
-
-	buf += i;
-	length -= i;
-
-	snprintf (buf, length, ")");
-
-finish:
-	/* ready for ATM callbacks */
-	instance->atm_dev->dev_data = instance;
-
-	usb_set_intfdata (intf, instance);
-
-	return 0;
-
-fail:
-	for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
-		kfree (instance->all_buffers[i].base);
-
-	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
-		usb_free_urb (instance->all_senders[i].urb);
-
-	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
-		struct udsl_receiver *rcv = &(instance->all_receivers[i]);
-
-		usb_free_urb (rcv->urb);
-
-		if (rcv->skb)
-			kfree_skb (rcv->skb);
-	}
-
-	kfree (instance);
-
-	return -ENOMEM;
-}
-
-static void udsl_usb_disconnect (struct usb_interface *intf)
-{
-	struct udsl_instance_data *instance = usb_get_intfdata (intf);
-	struct list_head *pos;
-	unsigned long flags;
-	unsigned int count = 0;
-	int result, i;
-
-	dbg ("disconnecting");
-
-	usb_set_intfdata (intf, NULL);
-
-	if (!instance) {
-		dbg ("NULL instance!");
-		return;
-	}
-
-	tasklet_disable (&instance->receive_tasklet);
-
-	/* receive finalize */
-	down (&instance->serialize); /* vs udsl_fire_receivers */
-	/* no need to take the spinlock */
-	list_for_each (pos, &instance->spare_receivers)
-		if (++count > UDSL_NUMBER_RCV_URBS)
-			panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
-	INIT_LIST_HEAD (&instance->spare_receivers);
-	up (&instance->serialize);
-
-	dbg ("udsl_usb_disconnect: flushed %u spare receivers", count);
-
-	count = UDSL_NUMBER_RCV_URBS - count;
-
-	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++)
-		if ((result = usb_unlink_urb (instance->all_receivers[i].urb)) < 0)
-			dbg ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d", i, result);
-
-	/* wait for completion handlers to finish */
-	do {
-		unsigned int completed = 0;
-
-		spin_lock_irqsave (&instance->completed_receivers_lock, flags);
-		list_for_each (pos, &instance->completed_receivers)
-			if (++completed > count)
-				panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
-		spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
-
-		dbg ("udsl_usb_disconnect: found %u completed receivers", completed);
-
-		if (completed == count)
-			break;
-
-		yield ();
-	} while (1);
-
-	dbg ("udsl_usb_disconnect: flushing");
-	/* no need to take the spinlock */
-	INIT_LIST_HEAD (&instance->completed_receivers);
-
-	tasklet_enable (&instance->receive_tasklet);
-	tasklet_kill (&instance->receive_tasklet);
-
-	dbg ("udsl_usb_disconnect: freeing receivers");
-	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
-		struct udsl_receiver *rcv = &(instance->all_receivers[i]);
-
-		usb_free_urb (rcv->urb);
-		kfree_skb (rcv->skb);
-	}
-
-	/* send finalize */
-	tasklet_disable (&instance->send_tasklet);
-
-	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
-		if ((result = usb_unlink_urb (instance->all_senders[i].urb)) < 0)
-			dbg ("udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d", i, result);
-
-	/* wait for completion handlers to finish */
-	do {
-		count = 0;
-		spin_lock_irqsave (&instance->send_lock, flags);
-		list_for_each (pos, &instance->spare_senders)
-			if (++count > UDSL_NUMBER_SND_URBS)
-				panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
-		spin_unlock_irqrestore (&instance->send_lock, flags);
-
-		dbg ("udsl_usb_disconnect: found %u spare senders", count);
-
-		if (count == UDSL_NUMBER_SND_URBS)
-			break;
-
-		yield ();
-	} while (1);
-
-	dbg ("udsl_usb_disconnect: flushing");
-	/* no need to take the spinlock */
-	INIT_LIST_HEAD (&instance->spare_senders);
-	INIT_LIST_HEAD (&instance->spare_buffers);
-	instance->current_buffer = NULL;
-
-	tasklet_enable (&instance->send_tasklet);
-
-	dbg ("udsl_usb_disconnect: freeing senders");
-	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
-		usb_free_urb (instance->all_senders[i].urb);
-
-	dbg ("udsl_usb_disconnect: freeing buffers");
-	for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
-		kfree (instance->all_buffers[i].base);
-
-	instance->usb_dev = NULL;
-
-	/* atm finalize */
-	shutdown_atm_dev (instance->atm_dev); /* frees instance */
-}
-
-
-/***************************************************************************
-*
-* Driver Init
-*
-****************************************************************************/
-
-static int __init udsl_usb_init (void)
-{
-	struct sk_buff *skb; /* dummy for sizeof */
-
-	dbg ("udsl_usb_init: driver version " DRIVER_VERSION);
-
-	if (sizeof (struct udsl_control) > sizeof (skb->cb)) {
-		printk (KERN_ERR __FILE__ ": unusable with this kernel!\n");
-		return -EIO;
-	}
-
-	return usb_register (&udsl_usb_driver);
-}
-
-static void __exit udsl_usb_cleanup (void)
-{
-	dbg ("udsl_usb_cleanup");
-
-	usb_deregister (&udsl_usb_driver);
-}
-
-module_init (udsl_usb_init);
-module_exit (udsl_usb_cleanup);
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
-
-
-#ifdef DEBUG_PACKET
-/*******************************************************************************
-*
-* Debug
-*
-*******************************************************************************/
-
-static int udsl_print_packet (const unsigned char *data, int len)
-{
-	unsigned char buffer [256];
-	int i = 0, j = 0;
-
-	for (i = 0; i < len;) {
-		buffer[0] = '\0';
-		sprintf (buffer, "%.3d :", i);
-		for (j = 0; (j < 16) && (i < len); j++, i++) {
-			sprintf (buffer, "%s %2.2x", buffer, data[i]);
-		}
-		dbg ("%s", buffer);
-	}
-	return i;
-}
-
-#endif				/* PACKETDEBUG */
diff -urN linux-2.5.65-bk1/drivers/usb/net/cdc-ether.c linux-2.5.65-bk2/drivers/usb/net/cdc-ether.c
--- linux-2.5.65-bk1/drivers/usb/net/cdc-ether.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/drivers/usb/net/cdc-ether.c	Mon Mar 31 12:39:51 2003
@@ -1064,15 +1064,23 @@
 // Used by driver's probe routine ////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-void log_device_info(ether_dev_t *ether_dev)
+static void log_device_info(ether_dev_t *ether_dev)
 {
 	int len;
 	int string_num;
-	unsigned char manu[256];
-	unsigned char prod[256];
-	unsigned char sern[256];
+	unsigned char *manu = NULL;
+	unsigned char *prod = NULL;
+	unsigned char *sern = NULL;
 	unsigned char *mac_addr;
 
+	manu = kmalloc(256, GFP_KERNEL);
+	prod = kmalloc(256, GFP_KERNEL);
+	sern = kmalloc(256, GFP_KERNEL);
+	if (!manu || !prod || !sern) {
+		dbg("no mem for log_device_info");
+		goto fini;
+	}
+
 	// Default empty strings in case we don't find a real one
 	manu[0] = 0x00;
 	prod[0] = 0x00;
@@ -1113,6 +1121,10 @@
 	      ether_dev->net->name, manu, prod, sern, mac_addr[0], 
 	      mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], 
 	      mac_addr[5] );
+fini:
+	kfree(manu);
+	kfree(prod);
+	kfree(sern);
 }
 
 /* Forward declaration */
diff -urN linux-2.5.65-bk1/drivers/usb/net/pegasus.c linux-2.5.65-bk2/drivers/usb/net/pegasus.c
--- linux-2.5.65-bk1/drivers/usb/net/pegasus.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/drivers/usb/net/pegasus.c	Mon Mar 31 12:39:51 2003
@@ -121,7 +121,7 @@
 	char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(size, GFP_DMA);
+	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer) {
 		warn("%s: looks like we're out of memory", __FUNCTION__);
 		return -ENOMEM;
@@ -170,7 +170,7 @@
 	char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(size, GFP_DMA);
+	buffer = kmalloc(size, GFP_KERNEL);
 	if (!buffer) {
 		warn("%s: looks like we're out of memory", __FUNCTION__);
 		return -ENOMEM;
@@ -218,7 +218,7 @@
 	char *tmp;
 	DECLARE_WAITQUEUE(wait, current);
 
-	tmp = kmalloc(1, GFP_DMA);
+	tmp = kmalloc(1, GFP_KERNEL);
 	if (!tmp) {
 		warn("%s: looks like we're out of memory", __FUNCTION__);
 		return -ENOMEM;
diff -urN linux-2.5.65-bk1/drivers/usb/serial/whiteheat.c linux-2.5.65-bk2/drivers/usb/serial/whiteheat.c
--- linux-2.5.65-bk1/drivers/usb/serial/whiteheat.c	Mon Mar 17 13:44:02 2003
+++ linux-2.5.65-bk2/drivers/usb/serial/whiteheat.c	Mon Mar 31 12:39:51 2003
@@ -783,7 +783,7 @@
 			if (info->mcr & UART_MCR_RTS)
 				modem_signals |= TIOCM_RTS;
 			
-			if (copy_to_user((unsigned int *)arg, &modem_signals, sizeof(unsigned int)));
+			if (copy_to_user((unsigned int *)arg, &modem_signals, sizeof(unsigned int)))
 				return -EFAULT;
 
 			break;
diff -urN linux-2.5.65-bk1/drivers/usb/usb-skeleton.c linux-2.5.65-bk2/drivers/usb/usb-skeleton.c
--- linux-2.5.65-bk1/drivers/usb/usb-skeleton.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/drivers/usb/usb-skeleton.c	Mon Mar 31 12:39:51 2003
@@ -1,5 +1,5 @@
 /*
- * USB Skeleton driver - 0.9
+ * USB Skeleton driver - 1.0
  *
  * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
  *
@@ -12,14 +12,17 @@
  * USB driver quickly.  The design of it is based on the usb-serial and
  * dc2xx drivers.
  *
- * Thanks to Oliver Neukum and David Brownell for their help in debugging
- * this driver.
+ * Thanks to Oliver Neukum, David Brownell, and Alan Stern for their help
+ * in debugging this driver.
  *
- * TODO:
- *	- fix urb->status race condition in write sequence
  *
  * History:
  *
+ * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and
+ *			disconnect.  Fix transfer amount in read().  Use
+ *			macros instead of magic numbers in probe().  Change
+ *			size variables to size_t.  Show how to eliminate
+ *			DMA bounce buffer.
  * 2002_12_12 - 0.9 - compile fixes and got rid of fixed minor array.
  * 2002_09_26 - 0.8 - changes due to USB core conversion to struct device
  *			driver.
@@ -33,7 +36,7 @@
  * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel
  * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people
  * 2001_05_01 - 0.1 - first version
- * 
+ *
  */
 
 #include <linux/config.h>
@@ -42,8 +45,8 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
 #include <linux/smp_lock.h>
+#include <linux/completion.h>
 #include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
@@ -60,7 +63,7 @@
 
 
 /* Version Information */
-#define DRIVER_VERSION "v0.4"
+#define DRIVER_VERSION "v1.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
 #define DRIVER_DESC "USB Skeleton Driver"
 
@@ -101,15 +104,16 @@
 	char			num_bulk_out;		/* number of bulk out endpoints we have */
 
 	unsigned char *		bulk_in_buffer;		/* the buffer to receive data */
-	int			bulk_in_size;		/* the size of the receive buffer */
+	size_t			bulk_in_size;		/* the size of the receive buffer */
 	__u8			bulk_in_endpointAddr;	/* the address of the bulk in endpoint */
 
 	unsigned char *		bulk_out_buffer;	/* the buffer to send data */
-	int			bulk_out_size;		/* the size of the send buffer */
+	size_t			bulk_out_size;		/* the size of the send buffer */
 	struct urb *		write_urb;		/* the urb used to send data */
 	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */
+	atomic_t		write_busy;		/* true iff write urb is busy */
+	struct completion	write_finished;		/* wait for the write to finish */
 
-	struct work_struct	work;			/* work queue entry for line discipline waking up */
 	int			open;			/* if the port is open or not */
 	struct semaphore	sem;			/* locks this structure */
 };
@@ -118,6 +122,8 @@
 /* the global usb devfs handle */
 extern devfs_handle_t usb_devfs_handle;
 
+/* prevent races between open() and disconnect() */
+static DECLARE_MUTEX (disconnect_sem);
 
 /* local function prototypes */
 static ssize_t skel_read	(struct file *file, char *buffer, size_t count, loff_t *ppos);
@@ -125,7 +131,7 @@
 static int skel_ioctl		(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
 static int skel_open		(struct inode *inode, struct file *file);
 static int skel_release		(struct inode *inode, struct file *file);
-	
+
 static int skel_probe		(struct usb_interface *intf, const struct usb_device_id *id);
 static void skel_disconnect	(struct usb_interface *intf);
 
@@ -138,7 +144,7 @@
  * to have a node in the /dev directory. If the USB
  * device were for a network interface then the driver
  * would use "struct net_driver" instead, and a serial
- * device would use "struct tty_driver". 
+ * device would use "struct tty_driver".
  */
 static struct file_operations skel_fops = {
 	/*
@@ -167,7 +173,7 @@
 	.ioctl =	skel_ioctl,
 	.open =		skel_open,
 	.release =	skel_release,
-};      
+};
 
 
 /* usb specific object needed to register this driver with the usb subsystem */
@@ -188,8 +194,8 @@
 
 	if (!debug)
 		return;
-	
-	printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", 
+
+	printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",
 		function, size);
 	for (i = 0; i < size; ++i) {
 		printk ("%.2x ", data[i]);
@@ -206,7 +212,9 @@
 	if (dev->bulk_in_buffer != NULL)
 		kfree (dev->bulk_in_buffer);
 	if (dev->bulk_out_buffer != NULL)
-		kfree (dev->bulk_out_buffer);
+		usb_buffer_free (dev->udev, dev->bulk_out_size,
+				dev->bulk_out_buffer,
+				dev->write_urb->transfer_dma);
 	if (dev->write_urb != NULL)
 		usb_free_urb (dev->write_urb);
 	kfree (dev);
@@ -222,22 +230,28 @@
 	struct usb_interface *interface;
 	int subminor;
 	int retval = 0;
-	
+
 	dbg("%s", __FUNCTION__);
 
 	subminor = minor (inode->i_rdev);
 
+	/* prevent disconnects */
+	down (&disconnect_sem);
+
 	interface = usb_find_interface (&skel_driver,
 					mk_kdev(USB_MAJOR, subminor));
 	if (!interface) {
 		err ("%s - error, can't find device for minor %d",
 		     __FUNCTION__, subminor);
-		return -ENODEV;
+		retval = -ENODEV;
+		goto exit_no_device;
 	}
-			
+
 	dev = usb_get_intfdata(interface);
-	if (!dev)
-		return -ENODEV;
+	if (!dev) {
+		retval = -ENODEV;
+		goto exit_no_device;
+	}
 
 	/* lock this device */
 	down (&dev->sem);
@@ -251,6 +265,8 @@
 	/* unlock this device */
 	up (&dev->sem);
 
+exit_no_device:
+	up (&disconnect_sem);
 	return retval;
 }
 
@@ -280,6 +296,12 @@
 		goto exit_not_opened;
 	}
 
+	/* wait for any bulk writes that might be going on to finish up */
+	if (atomic_read (&dev->write_busy))
+		wait_for_completion (&dev->write_finished);
+
+	dev->open = 0;
+
 	if (dev->udev == NULL) {
 		/* the device was unplugged before the file was released */
 		up (&dev->sem);
@@ -287,11 +309,6 @@
 		return 0;
 	}
 
-	/* shutdown any bulk writes that might be going on */
-	usb_unlink_urb (dev->write_urb);
-
-	dev->open = 0;
-
 exit_not_opened:
 	up (&dev->sem);
 
@@ -308,7 +325,7 @@
 	int retval = 0;
 
 	dev = (struct usb_skel *)file->private_data;
-	
+
 	dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count);
 
 	/* lock this object */
@@ -319,12 +336,13 @@
 		up (&dev->sem);
 		return -ENODEV;
 	}
-	
-	/* do an immediate bulk read to get data from the device */
+
+	/* do a blocking bulk read to get data from the device */
 	retval = usb_bulk_msg (dev->udev,
-			       usb_rcvbulkpipe (dev->udev, 
+			       usb_rcvbulkpipe (dev->udev,
 						dev->bulk_in_endpointAddr),
-			       dev->bulk_in_buffer, dev->bulk_in_size,
+			       dev->bulk_in_buffer,
+			       min (dev->bulk_in_size, count),
 			       &count, HZ*10);
 
 	/* if the read was successful, copy the data to userspace */
@@ -334,7 +352,7 @@
 		else
 			retval = count;
 	}
-	
+
 	/* unlock the device */
 	up (&dev->sem);
 	return retval;
@@ -343,6 +361,18 @@
 
 /**
  *	skel_write
+ *
+ *	A device driver has to decide how to report I/O errors back to the
+ *	user.  The safest course is to wait for the transfer to finish before
+ *	returning so that any errors will be reported reliably.  skel_read()
+ *	works like this.  But waiting for I/O is slow, so many drivers only
+ *	check for errors during I/O initiation and do not report problems
+ *	that occur during the actual transfer.  That's what we will do here.
+ *
+ *	A driver concerned with maximum I/O throughput would use double-
+ *	buffering:  Two urbs would be devoted to write transfers, so that
+ *	one urb could always be active while the other was waiting for the
+ *	user to send more data.
  */
 static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
@@ -369,37 +399,38 @@
 		goto exit;
 	}
 
-	/* see if we are already in the middle of a write */
-	if (dev->write_urb->status == -EINPROGRESS) {
-		dbg ("%s - already writing", __FUNCTION__);
-		goto exit;
-	}
+	/* wait for a previous write to finish up; we don't use a timeout
+	 * and so a nonresponsive device can delay us indefinitely.
+	 */
+	if (atomic_read (&dev->write_busy))
+		wait_for_completion (&dev->write_finished);
 
-	/* we can only write as much as 1 urb will hold */
-	bytes_written = (count > dev->bulk_out_size) ? 
-				dev->bulk_out_size : count;
+	/* we can only write as much as our buffer will hold */
+	bytes_written = min (dev->bulk_out_size, count);
 
-	/* copy the data from userspace into our urb */
-	if (copy_from_user(dev->write_urb->transfer_buffer, buffer, 
+	/* copy the data from userspace into our transfer buffer;
+	 * this is the only copy required.
+	 */
+	if (copy_from_user(dev->write_urb->transfer_buffer, buffer,
 			   bytes_written)) {
 		retval = -EFAULT;
 		goto exit;
 	}
 
-	usb_skel_debug_data (__FUNCTION__, bytes_written, 
+	usb_skel_debug_data (__FUNCTION__, bytes_written,
 			     dev->write_urb->transfer_buffer);
 
-	/* set up our urb */
-	usb_fill_bulk_urb(dev->write_urb, dev->udev, 
-		      usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
-		      dev->write_urb->transfer_buffer, bytes_written,
-		      skel_write_bulk_callback, dev);
+	/* this urb was already set up, except for this write size */
+	dev->write_urb->transfer_buffer_length = bytes_written;
 
 	/* send the data out the bulk port */
 	/* a character device write uses GFP_KERNEL,
 	 unless a spinlock is held */
+	init_completion (&dev->write_finished);
+	atomic_set (&dev->write_busy, 1);
 	retval = usb_submit_urb(dev->write_urb, GFP_KERNEL);
 	if (retval) {
+		atomic_set (&dev->write_busy, 0);
 		err("%s - failed submitting write urb, error %d",
 		    __FUNCTION__, retval);
 	} else {
@@ -435,12 +466,11 @@
 	dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __FUNCTION__,
 	    dev->minor, cmd, arg);
 
-
 	/* fill in your device specific stuff here */
-	
+
 	/* unlock the device */
 	up (&dev->sem);
-	
+
 	/* return that we did not understand this ioctl call */
 	return -ENOTTY;
 }
@@ -455,14 +485,16 @@
 
 	dbg("%s - minor %d", __FUNCTION__, dev->minor);
 
-	if ((urb->status != -ENOENT) && 
-	    (urb->status != -ECONNRESET)) {
+	/* sync/async unlink faults aren't errors */
+	if (urb->status && !(urb->status == -ENOENT ||
+				urb->status == -ECONNRESET)) {
 		dbg("%s - nonzero write bulk status received: %d",
 		    __FUNCTION__, urb->status);
-		return;
 	}
 
-	return;
+	/* notify anyone waiting that the write has finished */
+	atomic_set (&dev->write_busy, 0);
+	complete (&dev->write_finished);
 }
 
 
@@ -479,12 +511,12 @@
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
 	int minor;
-	int buffer_size;
+	size_t buffer_size;
 	int i;
 	int retval;
 	char name[10];
 
-	
+
 	/* See if the device offered us matches what we can accept */
 	if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) ||
 	    (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) {
@@ -513,12 +545,15 @@
 
 	/* set up the endpoint information */
 	/* check out the endpoints */
+	/* use only the first bulk-in and bulk-out endpoints */
 	iface_desc = &interface->altsetting[0];
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		endpoint = &iface_desc->endpoint[i].desc;
 
-		if ((endpoint->bEndpointAddress & 0x80) &&
-		    ((endpoint->bmAttributes & 3) == 0x02)) {
+		if (!dev->bulk_in_endpointAddr &&
+		    (endpoint->bEndpointAddress & USB_DIR_IN) &&
+		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+					== USB_ENDPOINT_XFER_BULK)) {
 			/* we found a bulk in endpoint */
 			buffer_size = endpoint->wMaxPacketSize;
 			dev->bulk_in_size = buffer_size;
@@ -529,9 +564,11 @@
 				goto error;
 			}
 		}
-		
-		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
-		    ((endpoint->bmAttributes & 3) == 0x02)) {
+
+		if (!dev->bulk_out_endpointAddr &&
+		    !(endpoint->bEndpointAddress & USB_DIR_IN) &&
+		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+					== USB_ENDPOINT_XFER_BULK)) {
 			/* we found a bulk out endpoint */
 			/* a probe() may sleep and has no restrictions on memory allocations */
 			dev->write_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -539,40 +576,56 @@
 				err("No free urbs available");
 				goto error;
 			}
+			dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+
+			/* on some platforms using this kind of buffer alloc
+			 * call eliminates a dma "bounce buffer".
+			 *
+			 * NOTE: you'd normally want i/o buffers that hold
+			 * more than one packet, so that i/o delays between
+			 * packets don't hurt throughput.
+			 */
 			buffer_size = endpoint->wMaxPacketSize;
 			dev->bulk_out_size = buffer_size;
-			dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
-			dev->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+			dev->write_urb->transfer_flags = (URB_NO_DMA_MAP |
+					URB_ASYNC_UNLINK);
+			dev->bulk_out_buffer = usb_buffer_alloc (udev,
+					buffer_size, GFP_KERNEL,
+					&dev->write_urb->transfer_dma);
 			if (!dev->bulk_out_buffer) {
 				err("Couldn't allocate bulk_out_buffer");
 				goto error;
 			}
-			usb_fill_bulk_urb(dev->write_urb, udev, 
-				      usb_sndbulkpipe(udev, 
+			usb_fill_bulk_urb(dev->write_urb, udev,
+				      usb_sndbulkpipe(udev,
 						      endpoint->bEndpointAddress),
 				      dev->bulk_out_buffer, buffer_size,
 				      skel_write_bulk_callback, dev);
 		}
 	}
+	if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
+		err("Couldn't find both bulk-in and bulk-out endpoints");
+		goto error;
+	}
 
 	/* initialize the devfs node for this device and register it */
 	sprintf(name, "skel%d", dev->minor);
-	
+
 	dev->devfs = devfs_register (usb_devfs_handle, name,
 				     DEVFS_FL_DEFAULT, USB_MAJOR,
 				     dev->minor,
-				     S_IFCHR | S_IRUSR | S_IWUSR | 
-				     S_IRGRP | S_IWGRP | S_IROTH, 
+				     S_IFCHR | S_IRUSR | S_IWUSR |
+				     S_IRGRP | S_IWGRP | S_IROTH,
 				     &skel_fops, NULL);
 
 	/* let the user know what node this device is now attached to */
-	info ("USB Skeleton device now attached to USBSkel%d", dev->minor);
+	info ("USB Skeleton device now attached to USBSkel-%d", dev->minor);
 
 	/* add device id so the device works when advertised */
 	interface->kdev = mk_kdev(USB_MAJOR, dev->minor);
 
 	goto exit;
-	
+
 error:
 	skel_delete (dev);
 	dev = NULL;
@@ -593,12 +646,21 @@
  *	skel_disconnect
  *
  *	Called by the usb core when the device is removed from the system.
+ *
+ *	This routine guarantees that the driver will not submit any more urbs
+ *	by clearing dev->udev.  It is also supposed to terminate any currently
+ *	active urbs.  Unfortunately, usb_bulk_msg(), used in skel_read(), does
+ *	not provide any way to do this.  But at least we can cancel an active
+ *	write.
  */
 static void skel_disconnect(struct usb_interface *interface)
 {
 	struct usb_skel *dev;
 	int minor;
 
+	/* prevent races with open() */
+	down (&disconnect_sem);
+
 	dev = usb_get_intfdata (interface);
 	usb_set_intfdata (interface, NULL);
 
@@ -606,7 +668,7 @@
 		return;
 
 	down (&dev->sem);
-		
+
 	/* remove device id to disable open() */
 	interface->kdev = NODEV;
 
@@ -617,15 +679,21 @@
 
 	/* give back our dynamic minor */
 	usb_deregister_dev (1, minor);
-	
+
+	/* terminate an ongoing write */
+	if (atomic_read (&dev->write_busy)) {
+		usb_unlink_urb (dev->write_urb);
+		wait_for_completion (&dev->write_finished);
+	}
+
+	dev->udev = NULL;
+	up (&dev->sem);
+
 	/* if the device is not opened, then we clean up right now */
-	if (!dev->open) {
-		up (&dev->sem);
+	if (!dev->open)
 		skel_delete (dev);
-	} else {
-		dev->udev = NULL;
-		up (&dev->sem);
-	}
+
+	up (&disconnect_sem);
 
 	info("USB Skeleton #%d now disconnected", minor);
 }
@@ -668,4 +736,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
diff -urN linux-2.5.65-bk1/drivers/video/Makefile linux-2.5.65-bk2/drivers/video/Makefile
--- linux-2.5.65-bk1/drivers/video/Makefile	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/drivers/video/Makefile	Mon Mar 31 12:39:51 2003
@@ -13,7 +13,7 @@
 endif
 
 obj-$(CONFIG_FB_ACORN)            += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_AMIGA)            += amifb.o
+obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p.o
 obj-$(CONFIG_FB_PM2)              += pm2fb.o
 obj-$(CONFIG_FB_PM3)		  += pm3fb.o
 obj-$(CONFIG_FB_APOLLO)           += dnfb.o cfbfillrect.o cfbimgblt.o
@@ -58,7 +58,7 @@
 obj-$(CONFIG_FB_MATROX)		  += matrox/
 obj-$(CONFIG_FB_RIVA)		  += riva/ cfbimgblt.o vgastate.o 
 obj-$(CONFIG_FB_SIS)		  += sis/
-obj-$(CONFIG_FB_ATY)		  += aty/ cfbimgblt.o cfbfillrect.o cfbimgblt.o
+obj-$(CONFIG_FB_ATY)		  += aty/ cfbimgblt.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_I810)             += i810/ cfbfillrect.o cfbcopyarea.o \
 	                             cfbimgblt.o vgastate.o
 
diff -urN linux-2.5.65-bk1/drivers/video/amifb.c linux-2.5.65-bk2/drivers/video/amifb.c
--- linux-2.5.65-bk1/drivers/video/amifb.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/drivers/video/amifb.c	Mon Mar 31 12:39:51 2003
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device
  *
- *    Copyright (C) 1995 Geert Uytterhoeven
+ *    Copyright (C) 1995-2003 Geert Uytterhoeven
  *
  *          with work by Roman Zippel
  *
@@ -62,10 +62,7 @@
 #include <asm/amigaints.h>
 #include <asm/setup.h>
 
-#include <video/fbcon.h>
-#include <video/fbcon-afb.h>
-#include <video/fbcon-ilbm.h>
-#include <video/fbcon-mfb.h>
+#include "c2p.h"
 
 
 #define DEBUG
@@ -613,12 +610,11 @@
 
 #define SPRITEMEMSIZE		(64*64/4) /* max 64*64*4 */
 #define DUMMYSPRITEMEMSIZE	(8)
+static u_long spritememory;
 
 #define CHIPRAM_SAFETY_LIMIT	(16384)
 
-static u_long videomemory, spritememory;
-static u_long videomemorysize;
-static u_long videomemory_phys;
+static u_long videomemory;
 
 	/*
 	 * This is the earliest allowed start of fetching display data.
@@ -660,6 +656,47 @@
 static u_short currentcop = 0;
 
 	/*
+	 * Hardware Cursor API Definitions
+	 * These used to be in linux/fb.h, but were preliminary and used by
+	 * amifb only anyway
+	 */
+
+#define FBIOGET_FCURSORINFO     0x4607
+#define FBIOGET_VCURSORINFO     0x4608
+#define FBIOPUT_VCURSORINFO     0x4609
+#define FBIOGET_CURSORSTATE     0x460A
+#define FBIOPUT_CURSORSTATE     0x460B
+
+
+struct fb_fix_cursorinfo {
+	__u16 crsr_width;		/* width and height of the cursor in */
+	__u16 crsr_height;		/* pixels (zero if no cursor)	*/
+	__u16 crsr_xsize;		/* cursor size in display pixels */
+	__u16 crsr_ysize;
+	__u16 crsr_color1;		/* colormap entry for cursor color1 */
+	__u16 crsr_color2;		/* colormap entry for cursor color2 */
+};
+
+struct fb_var_cursorinfo {
+	__u16 width;
+	__u16 height;
+	__u16 xspot;
+	__u16 yspot;
+	__u8 data[1];			/* field with [height][width]        */
+};
+
+struct fb_cursorstate {
+	__s16 xoffset;
+	__s16 yoffset;
+	__u16 mode;
+};
+
+#define FB_CURSOR_OFF		0
+#define FB_CURSOR_ON		1
+#define FB_CURSOR_FLASH		2
+
+
+	/*
 	 * Hardware Cursor
 	 */
 
@@ -738,28 +775,28 @@
 	u_short fmode;		/* vmode */
 } currentpar;
 
-static struct display disp;
 
-static struct fb_info fb_info;
+static struct fb_info fb_info = {
+    .fix = {
+	.id		= "Amiga ",
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.accel		= FB_ACCEL_AMIGABLITT
+    }
+};
 
 
 	/*
-	 * Since we can't read the palette on OCS/ECS, and since reading one
-	 * single color palette entry requires 5 expensive custom chip bus accesses
-	 * on AGA, we keep a copy of the current palette.
-	 * Note that the entries are always 24 bit!
+	 *  Saved color entry 0 so we can restore it when unblanking
 	 */
 
-#if defined(CONFIG_FB_AMIGA_AGA)
-static struct { u_char red, green, blue, pad; } palette[256];
-#else
-static struct { u_char red, green, blue, pad; } palette[32];
-#endif
+static u_char red0, green0, blue0;
+
 
 #if defined(CONFIG_FB_AMIGA_ECS)
 static u_short ecs_palette[32];
 #endif
 
+
 	/*
 	 * Latches for Display Changes during VBlank
 	 */
@@ -778,15 +815,6 @@
 static u_short is_lace = 0;		/* Screen is laced */
 
 	/*
-	 * Frame Buffer Name
-	 *
-	 * The rest of the name is filled in during initialization
-	 */
-
-static char amifb_name[16] = "Amiga ";
-
-
-	/*
 	 * Predefined Video Modes
 	 *
 	 */
@@ -1087,29 +1115,22 @@
 
 int amifb_setup(char*);
 
-static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
-static int amifb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int amifb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                           u_int transp, struct fb_info *info);
+static int amifb_check_var(struct fb_var_screeninfo *var,
+			   struct fb_info *info);
+static int amifb_set_par(struct fb_info *info);
+static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info);
 static int amifb_blank(int blank, struct fb_info *info);
-static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
+static int amifb_pan_display(struct fb_var_screeninfo *var,
 			     struct fb_info *info);
-static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int amifb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg, int con, struct fb_info *info);
-
-static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var,
-				       u_char *data, int con);
-static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var,
-				       u_char *data, int con);
-static int amifb_get_cursorstate(struct fb_cursorstate *state, int con);
-static int amifb_set_cursorstate(struct fb_cursorstate *state, int con);
+static void amifb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+static void amifb_copyarea(struct fb_info *info, struct fb_copyarea *region);
+static void amifb_imageblit(struct fb_info *info, struct fb_image *image);
+static int amifb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg,
+		       struct fb_info *info);
+
 
 	/*
 	 * Interface to the low level console driver
@@ -1117,8 +1138,6 @@
 
 int amifb_init(void);
 static void amifb_deinit(void);
-static int amifbcon_switch(int con, struct fb_info *info);
-static int amifbcon_updatevar(int con, struct fb_info *info);
 
 	/*
 	 * Internal routines
@@ -1133,29 +1152,20 @@
 	 * Hardware routines
 	 */
 
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amifb_par *par);
 static int ami_decode_var(struct fb_var_screeninfo *var,
                           struct amifb_par *par);
 static int ami_encode_var(struct fb_var_screeninfo *var,
                           struct amifb_par *par);
-static void ami_get_par(struct amifb_par *par);
-static void ami_set_var(struct fb_var_screeninfo *var);
-#ifdef DEBUG
-static void ami_set_par(struct amifb_par *par);
-#endif
 static void ami_pan_var(struct fb_var_screeninfo *var);
 static int ami_update_par(void);
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info);
 static void ami_update_display(void);
 static void ami_init_display(void);
 static void ami_do_blank(void);
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con);
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con);
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data);
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data);
+static int ami_get_cursorstate(struct fb_cursorstate *state);
+static int ami_set_cursorstate(struct fb_cursorstate *state);
 static void ami_set_sprite(void);
 static void ami_init_copper(void);
 static void ami_reinit_copper(void);
@@ -1165,14 +1175,15 @@
 
 static struct fb_ops amifb_ops = {
 	.owner		= THIS_MODULE,
-	.fb_get_fix	= amifb_get_fix,
-	.fb_get_var	= amifb_get_var,
-	.fb_set_var	= amifb_set_var,
-	.fb_get_cmap	= amifb_get_cmap,
-	.fb_set_cmap	= gen_set_cmap,
+	.fb_check_var	= amifb_check_var,
+	.fb_set_par	= amifb_set_par,
 	.fb_setcolreg	= amifb_setcolreg,
-	.fb_pan_display	= amifb_pan_display,
 	.fb_blank	= amifb_blank,
+	.fb_pan_display	= amifb_pan_display,
+	.fb_fillrect	= amifb_fillrect,
+	.fb_copyarea	= amifb_copyarea,
+	.fb_imageblit	= amifb_imageblit,
+	.fb_cursor	= soft_cursor,
 	.fb_ioctl	= amifb_ioctl,
 };
 
@@ -1217,8 +1228,6 @@
 {
 	char *this_opt;
 
-	fb_info.fontname[0] = '\0';
-
 	if (!options || !*options)
 		return 0;
 
@@ -1234,8 +1243,6 @@
 			amifb_ilbm = 1;
 		else if (!strncmp(this_opt, "monitorcap:", 11))
 			amifb_setup_mcap(this_opt+11);
-		else if (!strncmp(this_opt, "font:", 5))
-			strcpy(fb_info.fontname, this_opt+5);
 		else if (!strncmp(this_opt, "fstart:", 7))
 			min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
 		else
@@ -1248,293 +1255,975 @@
 	return 0;
 }
 
-	/*
-	 * Get the Fixed Part of the Display
-	 */
 
-static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
+static int amifb_check_var(struct fb_var_screeninfo *var,
+			   struct fb_info *info)
 {
+	int err;
 	struct amifb_par par;
 
-	if (con == -1)
-		ami_get_par(&par);
-	else {
-		int err;
+	/* Validate wanted screen parameters */
+	if ((err = ami_decode_var(var, &par)))
+		return err;
 
-		if ((err = ami_decode_var(&fb_display[con].var, &par)))
-			return err;
-	}
-	return ami_encode_fix(fix, &par);
+	/* Encode (possibly rounded) screen parameters */
+	ami_encode_var(var, &par);
+	return 0;
 }
 
-	/*
-	 * Get the User Defined Part of the Display
-	 */
 
-static int amifb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+static int amifb_set_par(struct fb_info *info)
 {
-	int err = 0;
-
-	if (con == -1) {
-		struct amifb_par par;
+	struct amifb_par *par = (struct amifb_par *)info->par;
 
-		ami_get_par(&par);
-		err = ami_encode_var(var, &par);
-	} else
-		*var = fb_display[con].var;
-	return err;
-}
-
-	/*
-	 * Set the User Defined Part of the Display
-	 */
+	do_vmode_pan = 0;
+	do_vmode_full = 0;
 
-static int amifb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-	int err, activate = var->activate;
-	int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-	struct amifb_par par;
+	/* Decode wanted screen parameters */
+	ami_decode_var(&info->var, par);
 
-	struct display *display;
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = &disp;	/* used during initialization */
+	/* Set new videomode */
+	ami_build_copper();
 
-	/*
-	 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
-	 * as FB_VMODE_SMOOTH_XPAN is only used internally
-	 */
+	/* Set VBlank trigger */
+	do_vmode_full = 1;
 
-	if (var->vmode & FB_VMODE_CONUPDATE) {
-		var->vmode |= FB_VMODE_YWRAP;
-		var->xoffset = display->var.xoffset;
-		var->yoffset = display->var.yoffset;
+	/* Update fix for new screen parameters */
+	if (par->bpp == 1) {
+		info->fix.type = FB_TYPE_PACKED_PIXELS;
+		info->fix.type_aux = 0;
+	} else if (amifb_ilbm) {
+		info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
+		info->fix.type_aux = par->next_line;
+	} else {
+		info->fix.type = FB_TYPE_PLANES;
+		info->fix.type_aux = 0;
 	}
-	if ((err = ami_decode_var(var, &par)))
-		return err;
-	ami_encode_var(var, &par);
-	if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-		oldxres = display->var.xres;
-		oldyres = display->var.yres;
-		oldvxres = display->var.xres_virtual;
-		oldvyres = display->var.yres_virtual;
-		oldbpp = display->var.bits_per_pixel;
-		display->var = *var;
-		if (oldxres != var->xres || oldyres != var->yres ||
-		    oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
-		    oldbpp != var->bits_per_pixel) {
-			struct fb_fix_screeninfo fix;
-
-			ami_encode_fix(&fix, &par);
-			display->visual = fix.visual;
-			display->type = fix.type;
-			display->type_aux = fix.type_aux;
-			display->ypanstep = fix.ypanstep;
-			display->ywrapstep = fix.ywrapstep;
-			display->line_length = fix.line_length;
-			display->can_soft_blank = 1;
-			display->inverse = amifb_inverse;
-			switch (fix.type) {
-#ifdef FBCON_HAS_ILBM
-			    case FB_TYPE_INTERLEAVED_PLANES:
-				display->dispsw = &fbcon_ilbm;
-				break;
-#endif
-#ifdef FBCON_HAS_AFB
-			    case FB_TYPE_PLANES:
-				display->dispsw = &fbcon_afb;
-				break;
-#endif
-#ifdef FBCON_HAS_MFB
-			    case FB_TYPE_PACKED_PIXELS:	/* depth == 1 */
-				display->dispsw = &fbcon_mfb;
-				break;
-#endif
-			    default:
-				display->dispsw = &fbcon_dummy;
-			}
-			if (fb_info.changevar)
-				(*fb_info.changevar)(con);
-		}
-		if (oldbpp != var->bits_per_pixel) {
-			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-				return err;
-			do_install_cmap(con, info);
-		}
-		if (con == info->currcon)
-			ami_set_var(&display->var);
+	info->fix.line_length = div8(upx(16<<maxfmode, par->vxres));
+
+	if (par->vmode & FB_VMODE_YWRAP) {
+		info->fix.ywrapstep = 1;
+		info->fix.xpanstep = 0;
+		info->fix.ypanstep = 0;
+	} else {
+		info->fix.ywrapstep = 0;
+		if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
+			info->fix.xpanstep = 1;
+		else
+			info->fix.xpanstep = 16<<maxfmode;
+		info->fix.ypanstep = 1;
 	}
 	return 0;
 }
 
+
 	/*
 	 * Pan or Wrap the Display
 	 *
 	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
 	 */
 
-static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
-				struct fb_info *info)
+static int amifb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
 {
 	if (var->vmode & FB_VMODE_YWRAP) {
-		if (var->yoffset<0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+		if (var->yoffset < 0 ||
+		    var->yoffset >= info->var.yres_virtual || var->xoffset)
 			return -EINVAL;
 	} else {
 		/*
 		 * TODO: There will be problems when xpan!=1, so some columns
 		 * on the right side will never be seen
 		 */
-		if (var->xoffset+fb_display[con].var.xres > upx(16<<maxfmode, fb_display[con].var.xres_virtual) ||
-		    var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+		if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) ||
+		    var->yoffset+info->var.yres > info->var.yres_virtual)
 			return -EINVAL;
 	}
-	if (con == info->currcon)
-		ami_pan_var(var);
-	fb_display[con].var.xoffset = var->xoffset;
-	fb_display[con].var.yoffset = var->yoffset;
+	ami_pan_var(var);
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
 	if (var->vmode & FB_VMODE_YWRAP)
-		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+		info->var.vmode |= FB_VMODE_YWRAP;
 	else
-		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+		info->var.vmode &= ~FB_VMODE_YWRAP;
 	return 0;
 }
 
-	/*
-	 * Get the Colormap
-	 */
 
-static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
+#if BITS_PER_LONG == 32
+#define BYTES_PER_LONG	4
+#define SHIFT_PER_LONG	5
+#elif BITS_PER_LONG == 64
+#define BYTES_PER_LONG	8
+#define SHIFT_PER_LONG	6
+#else
+#define Please update me
+#endif
+
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long comp(unsigned long a, unsigned long b,
+				 unsigned long mask)
 {
-	if (con == info->currcon) /* current console? */
-		return fb_get_cmap(cmap, kspc, ami_getcolreg, info);
-	else if (fb_display[con].cmap.len) /* non default colormap? */
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-			     cmap, kspc ? 0 : 2);
-	return 0;
+	return ((a ^ b) & mask) ^ b;
 }
-	
-	/*
-	 * Amiga Frame Buffer Specific ioctls
-	 */
 
-static int amifb_ioctl(struct inode *inode, struct file *file,
-                       u_int cmd, u_long arg, int con, struct fb_info *info)
+
+static inline unsigned long xor(unsigned long a, unsigned long b,
+				unsigned long mask)
 {
-	int i;
+	return (a & mask) ^ b;
+}
 
-	switch (cmd) {
-		case FBIOGET_FCURSORINFO : {
-			struct fb_fix_cursorinfo crsrfix;
-			
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
-			if (!i) {
-				i = amifb_get_fix_cursorinfo(&crsrfix, con);
-				copy_to_user((void *)arg, &crsrfix, sizeof(crsrfix));
-			}
-			return i;
-		}
-		case FBIOGET_VCURSORINFO : {
-			struct fb_var_cursorinfo crsrvar;
 
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
-			if (!i) {
-				i = amifb_get_var_cursorinfo(&crsrvar,
-					((struct fb_var_cursorinfo *)arg)->data, con);
-				copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar));
-			}
-			return i;
+    /*
+     *  Unaligned forward bit copy using 32-bit or 64-bit memory accesses
+     */
+
+static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
+		   int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	shift = dst_idx-src_idx;
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(*src, *dst, first);
+				dst++;
+				src++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				n -= 8;
+			}
+			while (n--)
+				*dst++ = *src++;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(*src, *dst, last);
 		}
-		case FBIOPUT_VCURSORINFO : {
-			struct fb_var_cursorinfo crsrvar;
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
 
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
-			if (!i) {
-				copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar));
-				i = amifb_set_var_cursorinfo(&crsrvar,
-					((struct fb_var_cursorinfo *)arg)->data, con);
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(*src >> right, *dst, first);
+			} else if (src_idx+n <= BITS_PER_LONG) {
+				// Single source word
+				*dst = comp(*src << left, *dst, first);
+			} else {
+				// 2 source words
+				d0 = *src++;
+				d1 = *src;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = *src++;
+			// Leading bits
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(d0 >> right, *dst, first);
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			} else {
+				// 2 source words
+				d1 = *src++;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+				d0 = d1;
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= right) {
+					// Single source word
+					*dst = comp(d0 << left, *dst, last);
+				} else {
+					// 2 source words
+					d1 = *src;
+					*dst = comp(d0 << left | d1 >> right,
+						    *dst, last);
+				}
 			}
-			return i;
 		}
-		case FBIOGET_CURSORSTATE : {
-			struct fb_cursorstate crsrstate;
+	}
+}
 
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
-			if (!i) {
-				i = amifb_get_cursorstate(&crsrstate, con);
-				copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate));
-			}
-			return i;
+
+    /*
+     *  Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
+     */
+
+static void bitcpy_rev(unsigned long *dst, int dst_idx,
+		       const unsigned long *src, int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	dst += (n-1)/BITS_PER_LONG;
+	src += (n-1)/BITS_PER_LONG;
+	if ((n-1) % BITS_PER_LONG) {
+		dst_idx += (n-1) % BITS_PER_LONG;
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= BITS_PER_LONG-1;
+		src_idx += (n-1) % BITS_PER_LONG;
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= BITS_PER_LONG-1;
+	}
+
+	shift = dst_idx-src_idx;
+	first = ~0UL << (BITS_PER_LONG-1-dst_idx);
+	last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if ((unsigned long)dst_idx+1 >= n) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(*src, *dst, first);
+				dst--;
+				src--;
+				n -= dst_idx+1;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				n -= 8;
+			}
+			while (n--)
+				*dst-- = *src--;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(*src, *dst, last);
 		}
-		case FBIOPUT_CURSORSTATE : {
-			struct fb_cursorstate crsrstate;
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
 
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
-			if (!i) {
-				copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate));
-				i = amifb_set_cursorstate(&crsrstate, con);
+		if ((unsigned long)dst_idx+1 >= n) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift < 0) {
+				// Single source word
+				*dst = comp(*src << left, *dst, first);
+			} else if (1+(unsigned long)src_idx >= n) {
+				// Single source word
+				*dst = comp(*src >> right, *dst, first);
+			} else {
+				// 2 source words
+				d0 = *src--;
+				d1 = *src;
+				*dst = comp(d0 >> right | d1 << left, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = *src--;
+			// Leading bits
+			if (shift < 0) {
+				// Single source word
+				*dst = comp(d0 << left, *dst, first);
+				dst--;
+				n -= dst_idx+1;
+			} else {
+				// 2 source words
+				d1 = *src--;
+				*dst = comp(d0 >> right | d1 << left, *dst,
+					    first);
+				d0 = d1;
+				dst--;
+				n -= dst_idx+1;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= left) {
+					// Single source word
+					*dst = comp(d0 >> right, *dst, last);
+				} else {
+					// 2 source words
+					d1 = *src;
+					*dst = comp(d0 >> right | d1 << left,
+						    *dst, last);
+				}
 			}
-			return i;
 		}
-#ifdef DEBUG
-		case FBCMD_GET_CURRENTPAR : {
-			struct amifb_par par;
+	}
+}
 
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amifb_par));
-			if (!i) {
-				ami_get_par(&par);
-				copy_to_user((void *)arg, &par, sizeof(struct amifb_par));
-			}
-			return i;
+
+    /*
+     *  Unaligned forward inverting bit copy using 32-bit or 64-bit memory
+     *  accesses
+     */
+
+static void bitcpy_not(unsigned long *dst, int dst_idx,
+		       const unsigned long *src, int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	shift = dst_idx-src_idx;
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(~*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(~*src, *dst, first);
+				dst++;
+				src++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				n -= 8;
+			}
+			while (n--)
+				*dst++ = ~*src++;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(~*src, *dst, last);
 		}
-		case FBCMD_SET_CURRENTPAR : {
-			struct amifb_par par;
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
 
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amifb_par));
-			if (!i) {
-				copy_from_user(&par, (void *)arg, sizeof(struct amifb_par));
-				ami_set_par(&par);
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(~*src >> right, *dst, first);
+			} else if (src_idx+n <= BITS_PER_LONG) {
+				// Single source word
+				*dst = comp(~*src << left, *dst, first);
+			} else {
+				// 2 source words
+				d0 = ~*src++;
+				d1 = ~*src;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = ~*src++;
+			// Leading bits
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(d0 >> right, *dst, first);
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			} else {
+				// 2 source words
+				d1 = ~*src++;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+				d0 = d1;
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= right) {
+					// Single source word
+					*dst = comp(d0 << left, *dst, last);
+				} else {
+					// 2 source words
+					d1 = ~*src;
+					*dst = comp(d0 << left | d1 >> right,
+						    *dst, last);
+				}
 			}
-			return i;
 		}
-#endif	/* DEBUG */
 	}
-	return -EINVAL;
 }
 
-	/*
-	 * Hardware Cursor
-	 */
 
-static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+    /*
+     *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
+     */
+
+static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
 {
-	return ami_get_fix_cursorinfo(fix, con);
+	unsigned long val = pat;
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+#if BITS_PER_LONG == 64
+	val |= val << 32;
+#endif
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (dst_idx+n <= BITS_PER_LONG) {
+		// Single word
+		if (last)
+			first &= last;
+		*dst = comp(val, *dst, first);
+	} else {
+		// Multiple destination words
+		// Leading bits
+		if (first) {
+			*dst = comp(val, *dst, first);
+			dst++;
+			n -= BITS_PER_LONG-dst_idx;
+		}
+
+		// Main chunk
+		n /= BITS_PER_LONG;
+		while (n >= 8) {
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			n -= 8;
+		}
+		while (n--)
+			*dst++ = val;
+
+		// Trailing bits
+		if (last)
+			*dst = comp(val, *dst, last);
+	}
 }
 
-static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+
+    /*
+     *  Unaligned 32-bit pattern xor using 32/64-bit memory accesses
+     */
+
+static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
 {
-	return ami_get_var_cursorinfo(var, data, con);
+	unsigned long val = pat;
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+#if BITS_PER_LONG == 64
+	val |= val << 32;
+#endif
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (dst_idx+n <= BITS_PER_LONG) {
+		// Single word
+		if (last)
+			first &= last;
+		*dst = xor(val, *dst, first);
+	} else {
+		// Multiple destination words
+		// Leading bits
+		if (first) {
+			*dst = xor(val, *dst, first);
+			dst++;
+			n -= BITS_PER_LONG-dst_idx;
+		}
+
+		// Main chunk
+		n /= BITS_PER_LONG;
+		while (n >= 4) {
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			n -= 4;
+		}
+		while (n--)
+			*dst++ ^= val;
+
+		// Trailing bits
+		if (last)
+			*dst = xor(val, *dst, last);
+	}
+}
+
+static inline void fill_one_line(int bpp, unsigned long next_plane,
+				 unsigned long *dst, int dst_idx, u32 n,
+				 u32 color)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+		if (!--bpp)
+			break;
+		color >>= 1;
+		dst_idx += next_plane*8;
+	}
+}
+
+static inline void xor_one_line(int bpp, unsigned long next_plane,
+				unsigned long *dst, int dst_idx, u32 n,
+				u32 color)
+{
+	while (color) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+		if (!--bpp)
+			break;
+		color >>= 1;
+		dst_idx += next_plane*8;
+	}
+}
+
+
+static void amifb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+{
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int dst_idx, x2, y2;
+	unsigned long *dst;
+
+	if (!rect->width || !rect->height)
+		return;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 * */
+	x2 = rect->dx + rect->width;
+	y2 = rect->dy + rect->height;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	rect->width = x2 - rect->dx;
+	rect->height = y2 - rect->dy;
+
+	dst = (unsigned long *)
+		((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+	dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+	dst_idx += rect->dy*par->next_line*8+rect->dx;
+	while (rect->height--) {
+		switch (rect->rop) {
+		    case ROP_COPY:
+			fill_one_line(info->var.bits_per_pixel,
+				      par->next_plane, dst, dst_idx,
+				      rect->width, rect->color);
+			break;
+
+		    case ROP_XOR:
+			xor_one_line(info->var.bits_per_pixel,
+				     par->next_plane, dst, dst_idx,
+				     rect->width, rect->color);
+			break;
+		}
+		dst_idx += par->next_line*8;
+	}
 }
 
-static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static inline void copy_one_line(int bpp, unsigned long next_plane,
+				 unsigned long *dst, int dst_idx,
+				 unsigned long *src, int src_idx, u32 n)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= (BITS_PER_LONG-1);
+		bitcpy(dst, dst_idx, src, src_idx, n);
+		if (!--bpp)
+			break;
+		dst_idx += next_plane*8;
+		src_idx += next_plane*8;
+	}
+}
+
+static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
+				     unsigned long *dst, int dst_idx,
+				     unsigned long *src, int src_idx, u32 n)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= (BITS_PER_LONG-1);
+		bitcpy_rev(dst, dst_idx, src, src_idx, n);
+		if (!--bpp)
+			break;
+		dst_idx += next_plane*8;
+		src_idx += next_plane*8;
+	}
+}
+
+
+static void amifb_copyarea(struct fb_info *info, struct fb_copyarea *area)
 {
-	return ami_set_var_cursorinfo(var, data, con);
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int x2, y2, old_dx, old_dy;
+	unsigned long *dst, *src;
+	int dst_idx, src_idx, height;
+	int rev_copy = 0;
+
+	/* clip the destination */
+	old_dx = area->dx;
+	old_dy = area->dy;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 */
+	x2 = area->dx + area->width;
+	y2 = area->dy + area->height;
+	area->dx = area->dx > 0 ? area->dx : 0;
+	area->dy = area->dy > 0 ? area->dy : 0;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	area->width = x2 - area->dx;
+	area->height = y2 - area->dy;
+
+	/* update sx1,sy1 */
+	area->sx += (area->dx - old_dx);
+	area->sy += (area->dy - old_dy);
+
+	height = area->height;
+
+	/* the source must be completely inside the virtual screen */
+	if (area->sx < 0 || area->sy < 0 ||
+	    (area->sx + area->width) > info->var.xres_virtual ||
+	    (area->sy + area->height) > info->var.yres_virtual)
+		return;
+
+	if (area->dy > area->sy ||
+	    (area->dy == area->sy && area->dx > area->sx)) {
+		area->dy += area->height;
+		area->sy += area->height;
+		rev_copy = 1;
+	}
+	dst = (unsigned long *)
+		((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+	src = dst;
+	dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+	src_idx = dst_idx;
+	dst_idx += area->dy*par->next_line*8+area->dx;
+	src_idx += area->sy*par->next_line*8+area->sx;
+	if (rev_copy) {
+		while (height--) {
+			dst_idx -= par->next_line*8;
+			src_idx -= par->next_line*8;
+			copy_one_line_rev(info->var.bits_per_pixel,
+					  par->next_plane, dst, dst_idx, src,
+					  src_idx, area->width);
+		}
+	} else {
+		while (height--) {
+			copy_one_line(info->var.bits_per_pixel,
+				      par->next_plane, dst, dst_idx, src,
+				      src_idx, area->width);
+			dst_idx += par->next_line*8;
+			src_idx += par->next_line*8;
+		}
+	}
+}
+
+
+static inline void expand_one_line(int bpp, unsigned long next_plane,
+				   unsigned long *dst, int dst_idx, u32 n,
+				   const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+    const unsigned long *src;
+    int src_idx;
+
+    while (1) {
+	dst += dst_idx >> SHIFT_PER_LONG;
+	dst_idx &= (BITS_PER_LONG-1);
+	if ((bgcolor ^ fgcolor) & 1) {
+	    src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1));
+	    src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8;
+	    if (fgcolor & 1)
+		bitcpy(dst, dst_idx, src, src_idx, n);
+	    else
+		bitcpy_not(dst, dst_idx, src, src_idx, n);
+	    /* set or clear */
+	} else
+	    bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
+	if (!--bpp)
+	    break;
+	bgcolor >>= 1;
+	fgcolor >>= 1;
+	dst_idx += next_plane*8;
+    }
 }
 
-static int amifb_get_cursorstate(struct fb_cursorstate *state, int con)
+
+static void amifb_imageblit(struct fb_info *info, struct fb_image *image)
 {
-	return ami_get_cursorstate(state, con);
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int x2, y2;
+	unsigned long *dst;
+	int dst_idx;
+	const char *src;
+	u32 dx, dy, width, height, pitch;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly like we are
+	 * doing here.
+	 */
+	x2 = image->dx + image->width;
+	y2 = image->dy + image->height;
+	dx = image->dx;
+	dy = image->dy;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	width  = x2 - dx;
+	height = y2 - dy;
+
+	if (image->depth == 1) {
+		dst = (unsigned long *)
+			((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+		dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+		dst_idx += dy*par->next_line*8+dx;
+		src = image->data;
+		pitch = (image->width+7)/8;
+		while (height--) {
+			expand_one_line(info->var.bits_per_pixel,
+					par->next_plane, dst, dst_idx, width,
+					src, image->bg_color,
+					image->fg_color);
+			dst_idx += par->next_line*8;
+			src += pitch;
+		}
+	} else {
+		c2p(info->screen_base, image->data, dx, dy, width, height,
+		    par->next_line, par->next_plane, image->width,
+		    info->var.bits_per_pixel);
+	}
 }
 
-static int amifb_set_cursorstate(struct fb_cursorstate *state, int con)
+
+	/*
+	 * Amiga Frame Buffer Specific ioctls
+	 */
+
+static int amifb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg,
+		       struct fb_info *info)
 {
-	return ami_set_cursorstate(state, con);
+	union {
+		struct fb_fix_cursorinfo fix;
+		struct fb_var_cursorinfo var;
+		struct fb_cursorstate state;
+	} crsr;
+	int i;
+
+	switch (cmd) {
+		case FBIOGET_FCURSORINFO:
+			i = ami_get_fix_cursorinfo(&crsr.fix);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.fix,
+					    sizeof(crsr.fix)) ? -EFAULT : 0;
+
+		case FBIOGET_VCURSORINFO:
+			i = ami_get_var_cursorinfo(&crsr.var,
+				((struct fb_var_cursorinfo *)arg)->data);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.var,
+					    sizeof(crsr.var)) ? -EFAULT : 0;
+
+		case FBIOPUT_VCURSORINFO:
+			if (copy_from_user(&crsr.var, (void *)arg,
+					   sizeof(crsr.var)))
+				return -EFAULT;
+			return ami_set_var_cursorinfo(&crsr.var,
+				((struct fb_var_cursorinfo *)arg)->data);
+
+		case FBIOGET_CURSORSTATE:
+			i = ami_get_cursorstate(&crsr.state);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.state,
+					    sizeof(crsr.state)) ? -EFAULT : 0;
+
+		case FBIOPUT_CURSORSTATE:
+			if (copy_from_user(&crsr.state, (void *)arg,
+					   sizeof(crsr.state)))
+				return -EFAULT;
+			return ami_set_cursorstate(&crsr.state);
+	}
+	return -EINVAL;
 }
 
 
@@ -1570,7 +2259,6 @@
 	int tag, i, err = 0;
 	u_long chipptr;
 	u_int defmode;
-	struct fb_var_screeninfo var;
 
 	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
 		return -ENXIO;
@@ -1600,7 +2288,7 @@
 	switch (amiga_chipset) {
 #ifdef CONFIG_FB_AMIGA_OCS
 		case CS_OCS:
-			strcat(amifb_name, "OCS");
+			strcat(fb_info.fix.id, "OCS");
 default_chipset:
 			chipset = TAG_OCS;
 			maxdepth[TAG_SHRES] = 0;	/* OCS means no SHRES */
@@ -1609,13 +2297,13 @@
 			maxfmode = TAG_FMODE_1;
 			defmode = amiga_vblank == 50 ? DEFMODE_PAL
 						     : DEFMODE_NTSC;
-			videomemorysize = VIDEOMEMSIZE_OCS;
+			fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
 			break;
 #endif /* CONFIG_FB_AMIGA_OCS */
 
 #ifdef CONFIG_FB_AMIGA_ECS
 		case CS_ECS:
-			strcat(amifb_name, "ECS");
+			strcat(fb_info.fix.id, "ECS");
 			chipset = TAG_ECS;
 			maxdepth[TAG_SHRES] = 2;
 			maxdepth[TAG_HIRES] = 4;
@@ -1629,15 +2317,15 @@
 							 : DEFMODE_NTSC;
 			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
 			    VIDEOMEMSIZE_ECS_1M)
-				videomemorysize = VIDEOMEMSIZE_ECS_2M;
+				fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
 			else
-				videomemorysize = VIDEOMEMSIZE_ECS_1M;
+				fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
 			break;
 #endif /* CONFIG_FB_AMIGA_ECS */
 
 #ifdef CONFIG_FB_AMIGA_AGA
 		case CS_AGA:
-			strcat(amifb_name, "AGA");
+			strcat(fb_info.fix.id, "AGA");
 			chipset = TAG_AGA;
 			maxdepth[TAG_SHRES] = 8;
 			maxdepth[TAG_HIRES] = 8;
@@ -1646,16 +2334,16 @@
 			defmode = DEFMODE_AGA;
 			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
 			    VIDEOMEMSIZE_AGA_1M)
-				videomemorysize = VIDEOMEMSIZE_AGA_2M;
+				fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
 			else
-				videomemorysize = VIDEOMEMSIZE_AGA_1M;
+				fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
 			break;
 #endif /* CONFIG_FB_AMIGA_AGA */
 
 		default:
 #ifdef CONFIG_FB_AMIGA_OCS
 			printk("Unknown graphics chipset, defaulting to OCS\n");
-			strcat(amifb_name, "Unknown");
+			strcat(fb_info.fix.id, "Unknown");
 			goto default_chipset;
 #else /* CONFIG_FB_AMIGA_OCS */
 			err = -ENXIO;
@@ -1698,31 +2386,25 @@
 	    fb_info.monspecs.vfmax = 90;
 	}
 
-	strcpy(fb_info.modename, amifb_name);
-	fb_info.changevar = NULL;
 	fb_info.node = NODEV;
 	fb_info.fbops = &amifb_ops;
-	fb_info.disp = &disp;
-	fb_info.currcon = 1;
-	fb_info.switch_con = &amifbcon_switch;
-	fb_info.updatevar = &amifbcon_updatevar;
+	fb_info.par = &currentpar;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
-	memset(&var, 0, sizeof(var));
 
-	if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
+	if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
 			  NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
 		err = -EINVAL;
 		goto amifb_error;
 	}
 
 	round_down_bpp = 0;
-	chipptr = chipalloc(videomemorysize+
+	chipptr = chipalloc(fb_info.fix.smem_len+
 	                    SPRITEMEMSIZE+
 	                    DUMMYSPRITEMEMSIZE+
 	                    COPINITSIZE+
 	                    4*COPLISTSIZE);
 
-	assignchunk(videomemory, u_long, chipptr, videomemorysize);
+	assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
 	assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
 	assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
 	assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
@@ -1734,11 +2416,12 @@
 	/*
 	 * access the videomem with writethrough cache
 	 */
-	videomemory_phys = (u_long)ZTWO_PADDR(videomemory);
-	videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize);
+	fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
+	videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
+						   fb_info.fix.smem_len);
 	if (!videomemory) {
 		printk("amifb: WARNING! unable to map videomem cached writethrough\n");
-		videomemory = ZTWO_VADDR(videomemory_phys);
+		videomemory = ZTWO_VADDR(fb_info.fix.smem_start);
 	}
 
 	fb_info.screen_base = (char *)videomemory;
@@ -1757,25 +2440,24 @@
 
 	ami_init_copper();
 
-	if (request_irq(IRQ_AMIGA_VERTB, amifb_interrupt, 0,
+	if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
 	                "fb vertb handler", &currentpar)) {
 		err = -EBUSY;
 		goto amifb_error;
 	}
 
-	amifb_set_var(&var, -1, &fb_info);
+	fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
 
 	if (register_framebuffer(&fb_info) < 0) {
 		err = -EINVAL;
 		goto amifb_error;
 	}
 
-	printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
-	       minor(fb_info.node), fb_info.modename,
-	       videomemorysize>>10);
+	printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+	       minor(fb_info.node), fb_info.fix.id, fb_info.fix.smem_len>>10);
 
 	return 0;
-	
+
 amifb_error:
 	amifb_deinit();
 	return err;
@@ -1783,33 +2465,12 @@
 
 static void amifb_deinit(void)
 {
-	chipfree();    
+	fb_dealloc_cmap(&fb_info.cmap);
+	chipfree();
 	release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
 	custom.dmacon = DMAF_ALL | DMAF_MASTER;
 }
 
-static int amifbcon_switch(int con, struct fb_info *info)
-{
-	/* Do we have to save the colormap? */
-	if (fb_display[info->currcon].cmap.len)
-		fb_get_cmap(&fb_display[info->currcon].cmap, 1, ami_getcolreg, info);
-
-	info->currcon = con;
-	ami_set_var(&fb_display[con].var);
-	/* Install new colormap */
-	do_install_cmap(con, info);
-	return 0;
-}
-
-	/*
-	 * Update the `var' structure (called by fbcon.c)
-	 */
-
-static int amifbcon_updatevar(int con, struct fb_info *info)
-{
-	ami_pan_var(&fb_display[con].var);
-	return 0;
-}
 
 	/*
 	 * Blank the display.
@@ -1821,6 +2482,10 @@
 	return 0;
 }
 
+	/*
+	 * Flash the cursor (called by VBlank interrupt)
+	 */
+
 static int flash_cursor(void)
 {
 	static int cursorcount = 1;
@@ -1875,50 +2540,6 @@
 /* --------------------------- Hardware routines --------------------------- */
 
 	/*
-	 * This function should fill in the `fix' structure based on the
-	 * values in the `par' structure.
-	 */
-
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amifb_par *par)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, amifb_name);
-	fix->smem_start = videomemory_phys;
-	fix->smem_len = videomemorysize;
-
-#ifdef FBCON_HAS_MFB
-	if (par->bpp == 1) {
-		fix->type = FB_TYPE_PACKED_PIXELS;
-		fix->type_aux = 0;
-	} else
-#endif
-	if (amifb_ilbm) {
-		fix->type = FB_TYPE_INTERLEAVED_PLANES;
-		fix->type_aux = par->next_line;
-	} else {
-		fix->type = FB_TYPE_PLANES;
-		fix->type_aux = 0;
-	}
-	fix->line_length = div8(upx(16<<maxfmode, par->vxres));
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-
-	if (par->vmode & FB_VMODE_YWRAP) {
-		fix->ywrapstep = 1;
-		fix->xpanstep = fix->ypanstep = 0;
-	} else {
-		fix->ywrapstep = 0;
-		if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
-			fix->xpanstep = 1;
-		else
-			fix->xpanstep = 16<<maxfmode;
-		fix->ypanstep = 1;
-	}
-	fix->accel = FB_ACCEL_AMIGABLITT;
-	return 0;
-}
-
-	/*
 	 * Get the video params out of `var'. If a value doesn't fit, round
 	 * it up, if it's too big, return -EINVAL.
 	 */
@@ -2074,7 +2695,7 @@
 			if (!IS_OCS) {
 				par->beamcon0 = BMC0_PAL;
 				par->bplcon3 |= BPC3_BRDRBLNK;
-			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 
+			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
 			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
 				par->beamcon0 = BMC0_PAL;
 				par->hsstop = 1;
@@ -2104,7 +2725,7 @@
 			if (!IS_OCS) {
 				par->beamcon0 = 0;
 				par->bplcon3 |= BPC3_BRDRBLNK;
-			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 
+			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
 			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
 				par->beamcon0 = 0;
 				par->hsstop = 1;
@@ -2235,14 +2856,14 @@
 	if (amifb_ilbm) {
 		par->next_plane = div8(upx(16<<maxfmode, par->vxres));
 		par->next_line = par->bpp*par->next_plane;
-		if (par->next_line * par->vyres > videomemorysize) {
+		if (par->next_line * par->vyres > fb_info.fix.smem_len) {
 			DPRINTK("too few video mem\n");
 			return -EINVAL;
 		}
 	} else {
 		par->next_line = div8(upx(16<<maxfmode, par->vxres));
 		par->next_plane = par->vyres*par->next_line;
-		if (par->next_plane * par->bpp > videomemorysize) {
+		if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
 			DPRINTK("too few video mem\n");
 			return -EINVAL;
 		}
@@ -2402,38 +3023,6 @@
 	return 0;
 }
 
-	/*
-	 * Get current hardware setting
-	 */
-
-static void ami_get_par(struct amifb_par *par)
-{
-	*par = currentpar;
-}
-
-	/*
-	 * Set new videomode
-	 */
-
-static void ami_set_var(struct fb_var_screeninfo *var)
-{
-	do_vmode_pan = 0;
-	do_vmode_full = 0;
-	ami_decode_var(var, &currentpar);
-	ami_build_copper();
-	do_vmode_full = 1;
-}
-
-#ifdef DEBUG
-static void ami_set_par(struct amifb_par *par)
-{
-	do_vmode_pan = 0;
-	do_vmode_full = 0;
-	currentpar = *par;
-	ami_build_copper();
-	do_vmode_full = 1;
-}
-#endif
 
 	/*
 	 * Pan or Wrap the Display
@@ -2506,16 +3095,16 @@
 		par->bpl1mod = par->bpl2mod;
 
 	if (par->yoffset) {
-		par->bplpt0 = videomemory_phys + par->next_line*par->yoffset + move;
+		par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move;
 		if (par->vmode & FB_VMODE_YWRAP) {
 			if (par->yoffset > par->vyres-par->yres) {
-				par->bplpt0wrap = videomemory_phys + move;
+				par->bplpt0wrap = fb_info.fix.smem_start + move;
 				if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
 					par->bplpt0wrap += par->next_line;
 			}
 		}
 	} else
-		par->bplpt0 = videomemory_phys + move;
+		par->bplpt0 = fb_info.fix.smem_start + move;
 
 	if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
 		par->bplpt0 += par->next_line;
@@ -2523,45 +3112,6 @@
 	return 0;
 }
 
-	/*
-	 * Read a single color register and split it into
-	 * colors/transparent. Return != 0 for invalid regno.
-	 */
-
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info)
-{
-	int len, tr, tg, tb;
-
-	if (IS_AGA) {
-		if (regno > 255)
-			return 1;
-		len = 8;
-	} else if (currentpar.bplcon0 & BPC0_SHRES) {
-		if (regno > 3)
-			return 1;
-		len = 2;
-	} else {
-		if (regno > 31)
-			return 1;
-		len = 4;
-	}
-	tr = palette[regno].red>>(8-len);
-	tg = palette[regno].green>>(8-len);
-	tb = palette[regno].blue>>(8-len);
-	while (len < 16) {
-		tr |= tr<<len;
-		tg |= tg<<len;
-		tb |= tb<<len;
-		len <<= 1;
-	}
-	*red = tr;
-	*green = tg;
-	*blue = tb;
-	*transp = 0;
-	return 0;
-}
-
 
 	/*
 	 * Set a single color register. The values supplied are already
@@ -2585,9 +3135,11 @@
 	red >>= 8;
 	green >>= 8;
 	blue >>= 8;
-	palette[regno].red = red;
-	palette[regno].green = green;
-	palette[regno].blue = blue;
+	if (!regno) {
+		red0 = red;
+		green0 = green;
+		blue0 = blue;
+	}
 
 	/*
 	 * Update the corresponding Hardware Color Register, unless it's Color
@@ -2650,6 +3202,7 @@
 static void ami_init_display(void)
 {
 	struct amifb_par *par = &currentpar;
+	int i;
 
 	custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
 	custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
@@ -2685,18 +3238,16 @@
 	is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
 #if 1
 	if (is_lace) {
-		if (custom.vposr & 0x8000)
-			custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
-		else
-			custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]);
+		i = custom.vposr >> 15;
 	} else {
 		custom.vposw = custom.vposr | 0x8000;
-		custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
+		i = 1;
 	}
 #else
+	i = 1;
 	custom.vposw = custom.vposr | 0x8000;
-	custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
 #endif
+	custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
 }
 
 	/*
@@ -2744,9 +3295,9 @@
 		}
 	} else {
 		custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
-		red = palette[0].red;
-		green = palette[0].green;
-		blue = palette[0].blue;
+		red = red0;
+		green = green0;
+		blue = blue0;
 		if (!IS_OCS) {
 			custom.hsstrt = hsstrt2hw(par->hsstrt);
 			custom.hsstop = hsstop2hw(par->hsstop);
@@ -2782,11 +3333,7 @@
 	is_blanked = do_blank > 0 ? do_blank : 0;
 }
 
-	/*
-	 * Flash the cursor (called by VBlank interrupt)
-	 */
-
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
 {
 	struct amifb_par *par = &currentpar;
 
@@ -2797,7 +3344,7 @@
 	return 0;
 }
 
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data)
 {
 	struct amifb_par *par = &currentpar;
 	register u_short *lspr, *sspr;
@@ -2846,7 +3393,7 @@
 				"swap %1 ; lslw #1,%1 ; roxlb #1,%0"
 				: "=d" (color), "=d" (datawords) : "1" (datawords));
 #else
-			color = (((datawords >> 30) & 2) 
+			color = (((datawords >> 30) & 2)
 				 | ((datawords >> 15) & 1));
 			datawords <<= 1;
 #endif
@@ -2872,7 +3419,7 @@
 	return 0;
 }
 
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data)
 {
 	struct amifb_par *par = &currentpar;
 	register u_short *lspr, *sspr;
@@ -2991,7 +3538,7 @@
 	return 0;
 }
 
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
+static int ami_get_cursorstate(struct fb_cursorstate *state)
 {
 	struct amifb_par *par = &currentpar;
 
@@ -3001,7 +3548,7 @@
 	return 0;
 }
 
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
+static int ami_set_cursorstate(struct fb_cursorstate *state)
 {
 	struct amifb_par *par = &currentpar;
 
@@ -3062,6 +3609,7 @@
 	}
 }
 
+
 	/*
 	 * Initialise the Copper Initialisation List
 	 */
diff -urN linux-2.5.65-bk1/drivers/video/c2p.c linux-2.5.65-bk2/drivers/video/c2p.c
--- linux-2.5.65-bk1/drivers/video/c2p.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/drivers/video/c2p.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,229 @@
+/*
+ *  Fast C2P (Chunky-to-Planar) Conversion
+ *
+ *  Copyright (C) 2003 Geert Uytterhoeven
+ *
+ *  NOTES:
+ *    - This code was inspired by Scout's C2P tutorial
+ *    - It assumes to run on a big endian system
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#include <linux/string.h>
+#include "c2p.h"
+
+
+    /*
+     *  Basic transpose step
+     */
+
+#define _transp(d, i1, i2, shift, mask)			\
+    do {						\
+	u32 t = (d[i1] ^ (d[i2] >> shift)) & mask;	\
+	d[i1] ^= t;					\
+	d[i2] ^= t << shift;				\
+    } while (0)
+
+static inline u32 get_mask(int n)
+{
+    switch (n) {
+	case 1:
+	    return 0x55555555;
+	    break;
+
+	case 2:
+	    return 0x33333333;
+	    break;
+
+	case 4:
+	    return 0x0f0f0f0f;
+	    break;
+
+	case 8:
+	    return 0x00ff00ff;
+	    break;
+
+	case 16:
+	    return 0x0000ffff;
+	    break;
+    }
+    return 0;
+}
+
+#define transp_nx1(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	/* First block */				\
+	_transp(d, 0, 1, n, mask);			\
+	/* Second block */				\
+	_transp(d, 2, 3, n, mask);			\
+	/* Third block */				\
+	_transp(d, 4, 5, n, mask);			\
+	/* Fourth block */				\
+	_transp(d, 6, 7, n, mask);			\
+    } while (0)
+
+#define transp_nx2(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	/* First block */				\
+	_transp(d, 0, 2, n, mask);			\
+	_transp(d, 1, 3, n, mask);			\
+	/* Second block */				\
+	_transp(d, 4, 6, n, mask);			\
+	_transp(d, 5, 7, n, mask);			\
+    } while (0)
+
+#define transp_nx4(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	_transp(d, 0, 4, n, mask);			\
+	_transp(d, 1, 5, n, mask);			\
+	_transp(d, 2, 6, n, mask);			\
+	_transp(d, 3, 7, n, mask);			\
+    } while (0)
+
+#define transp(d, n, m)	transp_nx ## m(d, n)
+
+
+    /*
+     *  Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words
+     *  containing
+     *    - 32 8-bit chunky pixels on input
+     *    - permuted planar data on output
+     */
+
+static void c2p_8bpp(u32 d[8])
+{
+    transp(d, 16, 4);
+    transp(d, 8, 2);
+    transp(d, 4, 1);
+    transp(d, 2, 4);
+    transp(d, 1, 2);
+}
+
+
+    /*
+     *  Array containing the permution indices of the planar data after c2p
+     */
+
+static const int perm_c2p_8bpp[8] = { 7, 5, 3, 1, 6, 4, 2, 0 };
+
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long comp(unsigned long a, unsigned long b,
+				 unsigned long mask)
+{
+	return ((a ^ b) & mask) ^ b;
+}
+
+
+    /*
+     *  Store a full block of planar data after c2p conversion
+     */
+
+static inline void store_planar(char *dst, u32 dst_inc, u32 bpp, u32 d[8])
+{
+    int i;
+
+    for (i = 0; i < bpp; i++, dst += dst_inc)
+	*(u32 *)dst = d[perm_c2p_8bpp[i]];
+}
+
+
+    /*
+     *  Store a partial block of planar data after c2p conversion
+     */
+
+static inline void store_planar_masked(char *dst, u32 dst_inc, u32 bpp,
+				       u32 d[8], u32 mask)
+{
+    int i;
+
+    for (i = 0; i < bpp; i++, dst += dst_inc)
+	*(u32 *)dst = comp(d[perm_c2p_8bpp[i]], *(u32 *)dst, mask);
+}
+
+
+    /*
+     *  c2p - Copy 8-bit chunky image data to a planar frame buffer
+     *  @dst: Starting address of the planar frame buffer
+     *  @dx: Horizontal destination offset (in pixels)
+     *  @dy: Vertical destination offset (in pixels)
+     *  @width: Image width (in pixels)
+     *  @height: Image height (in pixels)
+     *  @dst_nextline: Frame buffer offset to the next line (in bytes)
+     *  @dst_nextplane: Frame buffer offset to the next plane (in bytes)
+     *  @src_nextline: Image offset to the next line (in bytes)
+     *  @bpp: Bits per pixel of the planar frame buffer (1-8)
+     */
+
+void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
+	 u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, u32 bpp)
+{
+    int dst_idx;
+    u32 d[8], first, last, w;
+    const u8 *c;
+    u8 *p;
+
+    dst += dy*dst_nextline+(dx & ~31);
+    dst_idx = dx % 32;
+    first = ~0UL >> dst_idx;
+    last = ~(~0UL >> ((dst_idx+width) % 32));
+    while (height--) {
+	c = src;
+	p = dst;
+	w = width;
+	if (dst_idx+width <= 32) {
+	    /* Single destination word */
+	    first &= last;
+	    memset(d, 0, sizeof(d));
+	    memcpy((u8 *)d+dst_idx, c, width);
+	    c += width;
+	    c2p_8bpp(d);
+	    store_planar_masked(p, dst_nextplane, bpp, d, first);
+	    p += 4;
+	} else {
+	    /* Multiple destination words */
+	    w = width;
+	    /* Leading bits */
+	    if (dst_idx) {
+		w = 32 - dst_idx;
+		memset(d, 0, dst_idx);
+		memcpy((u8 *)d+dst_idx, c, w);
+		c += w;
+		c2p_8bpp(d);
+		store_planar_masked(p, dst_nextplane, bpp, d, first);
+		p += 4;
+		w = width-w;
+	    }
+	    /* Main chunk */
+	    while (w >= 32) {
+		memcpy(d, c, 32);
+		c += 32;
+		c2p_8bpp(d);
+		store_planar(p, dst_nextplane, bpp, d);
+		p += 4;
+		w -= 32;
+	    }
+	    /* Trailing bits */
+	    w %= 32;
+	    if (w > 0) {
+		memcpy(d, c, w);
+		memset((u8 *)d+w, 0, 32-w);
+		c2p_8bpp(d);
+		store_planar_masked(p, dst_nextplane, bpp, d, last);
+	    }
+	}
+	src += src_nextline;
+	dst += dst_nextline;
+    }
+}
+
diff -urN linux-2.5.65-bk1/drivers/video/c2p.h linux-2.5.65-bk2/drivers/video/c2p.h
--- linux-2.5.65-bk1/drivers/video/c2p.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/drivers/video/c2p.h	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,16 @@
+/*
+ *  Fast C2P (Chunky-to-Planar) Conversion
+ *
+ *  Copyright (C) 2003 Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#include <linux/types.h>
+
+extern void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
+		u32 dst_nextline, u32 dst_nextplane, u32 src_nextline,
+		u32 bpp);
+
diff -urN linux-2.5.65-bk1/drivers/video/console/fbcon.c linux-2.5.65-bk2/drivers/video/console/fbcon.c
--- linux-2.5.65-bk1/drivers/video/console/fbcon.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/drivers/video/console/fbcon.c	Mon Mar 31 12:39:51 2003
@@ -456,7 +456,7 @@
 	region.color = attr_bgcol_ec(p, vc);
 	region.rop = ROP_COPY;
 
-	if (rw & !bottom_only) {
+	if (rw && !bottom_only) {
 		region.dx = info->var.xoffset + rs;
 		region.dy = 0;
 		region.width = rw;
diff -urN linux-2.5.65-bk1/drivers/video/dnfb.c linux-2.5.65-bk2/drivers/video/dnfb.c
--- linux-2.5.65-bk1/drivers/video/dnfb.c	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/drivers/video/dnfb.c	Mon Mar 31 12:39:51 2003
@@ -103,11 +103,6 @@
 
 #define SWAP(A) ((A>>8) | ((A&0xff) <<8))
 
-#if 0
-#define outb(a,d) *(char *)(a)=(d)
-#define outw(a,d) *(unsigned short *)a=d
-#endif
-
 static struct fb_info fb_info;
 
 /* frame buffer operations */
@@ -147,9 +142,9 @@
 static int dnfb_blank(int blank, struct fb_info *info)
 {
 	if (blank)
-		outb(0x0, AP_CONTROL_3A);
+		out_8(AP_CONTROL_3A, 0x0);
 	else
-		outb(0x1, AP_CONTROL_3A);
+		out_8(AP_CONTROL_3A, 0x1);
 	return 0;
 }
 
@@ -175,8 +170,8 @@
 		x_word_count = (x_end >> 4) - (area->dx >> 4) + 1;
 		start_mask = 0xffff0000 >> (area->dx & 0xf);
 		end_mask = 0x7ffff >> (x_end & 0xf);
-		outb((((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5),
-		     AP_CONTROL_0);
+		out_8(AP_CONTROL_0,
+		     (((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5));
 		if ((area->dx & 0xf) < (area->sx & 0xf))
 			pre_read = 1;
 	} else {
@@ -185,15 +180,16 @@
 		x_word_count = (area->dx >> 4) - (x_end >> 4) + 1;
 		start_mask = 0x7ffff >> (area->dx & 0xf);
 		end_mask = 0xffff0000 >> (x_end & 0xf);
-		outb(((-((area->sx & 0xf) - (area->dx & 0xf))) %
-		      16) | (0x4 << 5), AP_CONTROL_0);
+		out_8(AP_CONTROL_0,
+		     ((-((area->sx & 0xf) - (area->dx & 0xf))) % 16) |
+		     (0x4 << 5));
 		if ((area->dx & 0xf) > (area->sx & 0xf))
 			pre_read = 1;
 	}
 
 	for (i = 0; i < area->height; i++) {
 
-		outb(0xc | (dest >> 16), AP_CONTROL_3A);
+		out_8(AP_CONTROL_3A, 0xc | (dest >> 16));
 
 		if (pre_read) {
 			dummy = *src;
@@ -201,11 +197,11 @@
 		}
 
 		if (x_word_count) {
-			outb(start_mask, AP_WRITE_ENABLE);
+			out_8(AP_WRITE_ENABLE, start_mask);
 			*src = dest;
 			src += incr;
 			dest += incr;
-			outb(0, AP_WRITE_ENABLE);
+			out_8(AP_WRITE_ENABLE, 0);
 
 			for (j = 1; j < (x_word_count - 1); j++) {
 				*src = dest;
@@ -213,12 +209,12 @@
 				dest += incr;
 			}
 
-			outb(start_mask, AP_WRITE_ENABLE);
+			out_8(AP_WRITE_ENABLE, start_mask);
 			*src = dest;
 			dest += incr;
 			src += incr;
 		} else {
-			outb(start_mask | end_mask, AP_WRITE_ENABLE);
+			out_8(AP_WRITE_ENABLE, start_mask | end_mask);
 			*src = dest;
 			dest += incr;
 			src += incr;
@@ -226,7 +222,7 @@
 		src += (y_delta / 16);
 		dest += (y_delta / 16);
 	}
-	outb(NORMAL_MODE, AP_CONTROL_0);
+	out_8(AP_CONTROL_0, NORMAL_MODE);
 }
 
 
@@ -247,12 +243,12 @@
 		panic("unable to register apollo frame buffer\n");
 
 	/* now we have registered we can safely setup the hardware */
-	outb(RESET_CREG, AP_CONTROL_3A);
-	outw(0x0, AP_WRITE_ENABLE);
-	outb(NORMAL_MODE, AP_CONTROL_0);
-	outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
-	outb(S_DATA_PLN, AP_CONTROL_2);
-	outw(SWAP(0x3), AP_ROP_1);
+	out_8(AP_CONTROL_3A, RESET_CREG);
+	out_be16(AP_WRITE_ENABLE, 0x0);
+	out_8(AP_CONTROL_0, NORMAL_MODE);
+	out_8(AP_CONTROL_1, (AD_BLT | DST_EQ_SRC | NORM_CREG1));
+	out_8(AP_CONTROL_2, S_DATA_PLN);
+	out_be16(AP_ROP_1, SWAP(0x3));
 
 	printk("apollo frame buffer alive and kicking !\n");
 	return mem_start;
diff -urN linux-2.5.65-bk1/fs/affs/super.c linux-2.5.65-bk2/fs/affs/super.c
--- linux-2.5.65-bk1/fs/affs/super.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/fs/affs/super.c	Mon Mar 31 12:39:51 2003
@@ -298,8 +298,7 @@
 	if (!sbi)
 		return -ENOMEM;
 	sb->s_fs_info = sbi;
-	memset(sbi, 0, sizeof(struct affs_sb_info));
-
+	memset(sbi, 0, sizeof(*sbi));
 	init_MUTEX(&sbi->s_bmlock);
 
 	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
diff -urN linux-2.5.65-bk1/fs/sysfs/file.c linux-2.5.65-bk2/fs/sysfs/file.c
--- linux-2.5.65-bk1/fs/sysfs/file.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/fs/sysfs/file.c	Mon Mar 31 12:39:51 2003
@@ -80,7 +80,7 @@
 	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
 	struct sysfs_ops * ops = buffer->ops;
 	int ret = 0;
-	size_t count;
+	ssize_t count;
 
 	if (!buffer->page)
 		buffer->page = (char *) __get_free_page(GFP_KERNEL);
diff -urN linux-2.5.65-bk1/include/asm-i386/processor.h linux-2.5.65-bk2/include/asm-i386/processor.h
--- linux-2.5.65-bk1/include/asm-i386/processor.h	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/include/asm-i386/processor.h	Mon Mar 31 12:39:51 2003
@@ -371,6 +371,10 @@
 	 * pads the TSS to be cacheline-aligned (size is 0x100)
 	 */
 	unsigned long __cacheline_filler[5];
+	/*
+	 * .. and then another 0x100 bytes for emergency kernel stack
+	 */
+	unsigned long stack[64];
 };
 
 struct thread_struct {
diff -urN linux-2.5.65-bk1/include/asm-i386/uaccess.h linux-2.5.65-bk2/include/asm-i386/uaccess.h
--- linux-2.5.65-bk1/include/asm-i386/uaccess.h	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/include/asm-i386/uaccess.h	Mon Mar 31 12:39:51 2003
@@ -47,7 +47,13 @@
 #define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
 
 /*
- * Uhhuh, this needs 33-bit arithmetic. We have a carry..
+ * Test whether a block of memory is a valid user space address.
+ * Returns 0 if the range is valid, nonzero otherwise.
+ *
+ * This is equivalent to the following test:
+ * (u33)addr + (u33)size >= (u33)current->addr_limit.seg
+ *
+ * This needs 33-bit arithmetic. We have a carry...
  */
 #define __range_ok(addr,size) ({ \
 	unsigned long flag,sum; \
@@ -58,6 +64,25 @@
 
 #ifdef CONFIG_X86_WP_WORKS_OK
 
+/**
+ * access_ok: - Checks if a user space pointer is valid
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
+ *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
+ *        to write to a block, it is always safe to read from it.
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns true (nonzero) if the memory block may be valid, false (zero)
+ * if it is definitely invalid.
+ *
+ * Note that, depending on architecture, this function probably just
+ * checks that the pointer is in the user space range - after calling
+ * this function, memory access functions may still return -EFAULT.
+ */
 #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
 
 #else
@@ -68,6 +93,23 @@
 
 #endif
 
+/**
+ * verify_area: - Obsolete, use access_ok()
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This function has been replaced by access_ok().
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns zero if the memory block may be valid, -EFAULT
+ * if it is definitely invalid.
+ *
+ * See access_ok() for more details.
+ */
 static inline int verify_area(int type, const void * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
@@ -118,7 +160,25 @@
 		:"=a" (ret),"=d" (x) \
 		:"0" (ptr))
 
+
 /* Careful: we have to cast the result to the type of the pointer for sign reasons */
+/**
+ * get_user: - Get a simple variable from user space.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
 #define get_user(x,ptr)							\
 ({	int __ret_gu,__val_gu;						\
 	switch(sizeof (*(ptr))) {					\
@@ -138,11 +198,70 @@
 
 extern void __put_user_bad(void);
 
+
+/**
+ * put_user: - Write a simple value into user space.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
 #define put_user(x,ptr)							\
   __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
+
+/**
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
 #define __get_user(x,ptr) \
   __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+
+/**
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
 #define __put_user(x,ptr) \
   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
@@ -263,6 +382,21 @@
  * If a store crosses a page boundary and gets a fault, the x86 will not write
  * anything, so this is accurate.
  */
+
+/**
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
 static inline unsigned long
 __copy_to_user(void *to, const void *from, unsigned long n)
 {
@@ -284,6 +418,23 @@
 	return __copy_to_user_ll(to, from, n);
 }
 
+/**
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
 static inline unsigned long
 __copy_from_user(void *to, const void *from, unsigned long n)
 {
@@ -305,6 +456,19 @@
 	return __copy_from_user_ll(to, from, n);
 }
 
+/**
+ * copy_to_user: - Copy a block of data into user space.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
 static inline unsigned long
 copy_to_user(void *to, const void *from, unsigned long n)
 {
@@ -313,6 +477,22 @@
 	return n;
 }
 
+/**
+ * copy_from_user: - Copy a block of data from user space.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
 static inline unsigned long
 copy_from_user(void *to, const void *from, unsigned long n)
 {
@@ -323,7 +503,23 @@
 
 long strncpy_from_user(char *dst, const char *src, long count);
 long __strncpy_from_user(char *dst, const char *src, long count);
+
+/**
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Get the size of a NULL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NULL.
+ * On exception, returns 0.
+ *
+ * If there is a limit on the length of a valid string, you may wish to
+ * consider using strnlen_user() instead.
+ */
 #define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+
 long strnlen_user(const char *str, long n);
 unsigned long clear_user(void *mem, unsigned long len);
 unsigned long __clear_user(void *mem, unsigned long len);
diff -urN linux-2.5.65-bk1/include/asm-m68k/amigahw.h linux-2.5.65-bk2/include/asm-m68k/amigahw.h
--- linux-2.5.65-bk1/include/asm-m68k/amigahw.h	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/include/asm-m68k/amigahw.h	Mon Mar 31 12:39:51 2003
@@ -324,7 +324,7 @@
 };
 #define TOD3000_CNTRL1_HOLD	0
 #define TOD3000_CNTRL1_FREE	9
-#define TOD_3000 ((struct tod3000 *)(zTwoBase+0xDC0000))
+#define tod_3000 ((*(volatile struct tod3000 *)(zTwoBase+0xDC0000)))
 
 struct tod2000 {
   unsigned int  :28, second2:4;	/* lower digit */
@@ -349,6 +349,6 @@
 #define TOD2000_CNTRL1_BUSY	(1<<1)
 #define TOD2000_CNTRL3_24HMODE	(1<<2)
 #define TOD2000_HOUR1_PM	(1<<2)
-#define TOD_2000 ((struct tod2000 *)(zTwoBase+0xDC0000))
+#define tod_2000 ((*(volatile struct tod2000 *)(zTwoBase+0xDC0000)))
 
 #endif /* _M68K_AMIGAHW_H */
diff -urN linux-2.5.65-bk1/include/asm-m68k/apollohw.h linux-2.5.65-bk2/include/asm-m68k/apollohw.h
--- linux-2.5.65-bk1/include/asm-m68k/apollohw.h	Mon Mar 17 13:44:14 2003
+++ linux-2.5.65-bk2/include/asm-m68k/apollohw.h	Mon Mar 31 12:39:51 2003
@@ -101,9 +101,4 @@
 
 #define isaIO2mem(x) (((((x) & 0x3f8)  << 7) | (((x) & 0xfc00) >> 6) | ((x) & 0x7)) + 0x40000 + IO_BASE)
 
-#define inb(addr) (*((volatile unsigned char *)(addr)))
-#define outb(val,addr) (*((volatile unsigned char *)(addr)) = (val))
-#define inw(addr) (*((volatile unsigned short *)(addr)))
-#define outw(val,addr) (*((volatile unsigned short *)(addr)) = (val))
-
 #endif
diff -urN linux-2.5.65-bk1/include/asm-m68k/io.h linux-2.5.65-bk2/include/asm-m68k/io.h
--- linux-2.5.65-bk1/include/asm-m68k/io.h	Mon Mar 17 13:44:14 2003
+++ linux-2.5.65-bk2/include/asm-m68k/io.h	Mon Mar 31 12:39:51 2003
@@ -162,7 +162,9 @@
 #ifdef CONFIG_GG2
     case GG2_ISA: return GG2_ISA_MEM_B(addr);
 #endif
-      /* FIXME: any ISA mem mapping for PCMCIA? */
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return addr;
+#endif
     default: return 0; /* avoid warnings, just in case */
     }
 }
@@ -176,6 +178,9 @@
 #ifdef CONFIG_GG2
     case GG2_ISA: return GG2_ISA_MEM_W(addr);
 #endif
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return addr;
+#endif
     default: return 0; /* avoid warnings, just in case */
     }
 }
@@ -187,9 +192,9 @@
 #define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val)))
 
 #define isa_readb(p)       in_8(isa_mtb(p))
-#define isa_readw(p)       in_le16(isa_mtw(p))
+#define isa_readw(p)       (ISA_SEX ? in_be16(isa_mtw(p)) : in_le16(isa_mtw(p)))
 #define isa_writeb(val,p)  out_8(isa_mtb(p),(val))
-#define isa_writew(val,p)  out_le16(isa_mtw(p),(val))
+#define isa_writew(val,p)  (ISA_SEX ? out_be16(isa_mtw(p),(val)) : out_le16(isa_mtw(p),(val)))
 
 static inline void isa_delay(void)
 {
diff -urN linux-2.5.65-bk1/include/asm-m68k/kmap_types.h linux-2.5.65-bk2/include/asm-m68k/kmap_types.h
--- linux-2.5.65-bk1/include/asm-m68k/kmap_types.h	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/include/asm-m68k/kmap_types.h	Mon Mar 31 12:39:51 2003
@@ -15,6 +15,8 @@
 	KM_PTE1,
 	KM_IRQ0,
 	KM_IRQ1,
+	KM_SOFTIRQ0,
+	KM_SOFTIRQ1,
 	KM_TYPE_NR
 };
 
diff -urN linux-2.5.65-bk1/include/asm-m68k/page.h linux-2.5.65-bk2/include/asm-m68k/page.h
--- linux-2.5.65-bk1/include/asm-m68k/page.h	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/include/asm-m68k/page.h	Mon Mar 31 12:39:51 2003
@@ -6,10 +6,13 @@
 /* PAGE_SHIFT determines the page size */
 #ifndef CONFIG_SUN3
 #define PAGE_SHIFT	(12)
-#define PAGE_SIZE	(4096)
 #else
 #define PAGE_SHIFT	(13)
-#define PAGE_SIZE	(8192)
+#endif
+#ifdef __ASSEMBLY__
+#define PAGE_SIZE	(1 << PAGE_SHIFT)
+#else
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
 #endif
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
@@ -142,7 +145,7 @@
 {
      if(x == 0)
 	  return 0;
-     if(x > PAGE_OFFSET)
+     if(x >= PAGE_OFFSET)
         return (x-PAGE_OFFSET);
      else
         return (x+0x2000000);
diff -urN linux-2.5.65-bk1/include/asm-m68k/rtc.h linux-2.5.65-bk2/include/asm-m68k/rtc.h
--- linux-2.5.65-bk1/include/asm-m68k/rtc.h	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/include/asm-m68k/rtc.h	Mon Mar 31 12:39:51 2003
@@ -14,23 +14,21 @@
 #ifdef __KERNEL__
 
 #include <linux/rtc.h>
+#include <asm/errno.h>
 #include <asm/machdep.h>
 
-/* a few implementation details for the emulation : */
-
 #define RTC_PIE 0x40		/* periodic interrupt enable */
 #define RTC_AIE 0x20		/* alarm interrupt enable */
 #define RTC_UIE 0x10		/* update-finished interrupt enable */
 
-extern void gen_rtc_interrupt(unsigned long);
-
 /* some dummy definitions */
+#define RTC_BATT_BAD 0x100	/* battery bad */
 #define RTC_SQWE 0x08		/* enable square-wave output */
 #define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
 #define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
 #define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
 
-static inline void get_rtc_time(struct rtc_time *time)
+static inline unsigned int get_rtc_time(struct rtc_time *time)
 {
 	/*
 	 * Only the values that we read from the RTC are set. We leave
@@ -39,6 +37,7 @@
 	 * by the RTC when initially set to a non-zero value.
 	 */
 	mach_hwclk(0, time);
+	return RTC_24H;
 }
 
 static inline int set_rtc_time(struct rtc_time *time)
@@ -52,7 +51,7 @@
 		return mach_get_ss();
 	else{
 		struct rtc_time h;
-
+		
 		get_rtc_time(&h);
 		return h.tm_sec;
 	}
@@ -72,7 +71,6 @@
 	else
 		return -EINVAL;
 }
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM__RTC_H */
diff -urN linux-2.5.65-bk1/include/asm-m68k/siginfo.h linux-2.5.65-bk2/include/asm-m68k/siginfo.h
--- linux-2.5.65-bk1/include/asm-m68k/siginfo.h	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/include/asm-m68k/siginfo.h	Mon Mar 31 12:39:51 2003
@@ -23,8 +23,11 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
+			int _overrun;		/* overrun count */
+			char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
+			sigval_t _sigval;	/* same as below */
+			int _sys_private;       /* not to be passed to user */
 		} _timer;
 
 		/* POSIX.1b signals */
diff -urN linux-2.5.65-bk1/include/asm-m68k/sun3-head.h linux-2.5.65-bk2/include/asm-m68k/sun3-head.h
--- linux-2.5.65-bk1/include/asm-m68k/sun3-head.h	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/include/asm-m68k/sun3-head.h	Mon Mar 31 12:39:51 2003
@@ -9,4 +9,4 @@
 #define FC_SUPERD    5
 #define FC_CPU      7
 
-#endif __SUN3_HEAD_H
+#endif /* __SUN3_HEAD_H */
diff -urN linux-2.5.65-bk1/include/asm-m68k/system.h linux-2.5.65-bk2/include/asm-m68k/system.h
--- linux-2.5.65-bk1/include/asm-m68k/system.h	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/include/asm-m68k/system.h	Mon Mar 31 12:39:51 2003
@@ -101,21 +101,24 @@
 	case 1:
 		tmp = *(u8 *)ptr;
 		*(u8 *)ptr = x;
+		x = tmp;
 		break;
 	case 2:
 		tmp = *(u16 *)ptr;
 		*(u16 *)ptr = x;
+		x = tmp;
 		break;
 	case 4:
 		tmp = *(u32 *)ptr;
 		*(u32 *)ptr = x;
+		x = tmp;
 		break;
 	default:
 		BUG();
 	}
 
 	local_irq_restore(flags);
-	return tmp;
+	return x;
 }
 #else
 static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
diff -urN linux-2.5.65-bk1/include/asm-m68k/unistd.h linux-2.5.65-bk2/include/asm-m68k/unistd.h
--- linux-2.5.65-bk1/include/asm-m68k/unistd.h	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/include/asm-m68k/unistd.h	Mon Mar 31 12:39:51 2003
@@ -239,7 +239,9 @@
 #define __NR_fremovexattr	234
 #define __NR_futex		235
 
-/* user-visible error numbers are in the range -1 - -122: see
+#define NR_syscalls		236
+
+/* user-visible error numbers are in the range -1 - -124: see
    <asm-m68k/errno.h> */
 
 #define __syscall_return(type, res) \
diff -urN linux-2.5.65-bk1/include/asm-sparc64/irq.h linux-2.5.65-bk2/include/asm-sparc64/irq.h
--- linux-2.5.65-bk1/include/asm-sparc64/irq.h	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/include/asm-sparc64/irq.h	Mon Mar 31 12:39:51 2003
@@ -117,8 +117,6 @@
 extern void disable_irq(unsigned int);
 #define disable_irq_nosync disable_irq
 extern void enable_irq(unsigned int);
-extern void sparc64_init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *),
-				unsigned long *);
 extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 extern unsigned int psycho_build_irq(void *psycho, int imap_off, int ino, int need_dma_sync);
diff -urN linux-2.5.65-bk1/include/asm-sparc64/spitfire.h linux-2.5.65-bk2/include/asm-sparc64/spitfire.h
--- linux-2.5.65-bk1/include/asm-sparc64/spitfire.h	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/include/asm-sparc64/spitfire.h	Mon Mar 31 12:39:51 2003
@@ -45,8 +45,6 @@
 
 extern enum ultra_tlb_layout tlb_type;
 
-#define SPARC64_USE_STICK	(tlb_type != spitfire)
-
 #define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
 
 #define L1DCACHE_SIZE		0x4000
diff -urN linux-2.5.65-bk1/include/asm-sparc64/thread_info.h linux-2.5.65-bk2/include/asm-sparc64/thread_info.h
--- linux-2.5.65-bk1/include/asm-sparc64/thread_info.h	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/include/asm-sparc64/thread_info.h	Mon Mar 31 12:39:51 2003
@@ -97,7 +97,7 @@
 #define TI_PCR		0x00000490
 #define TI_CEE_STUFF	0x00000498
 #define TI_RESTART_BLOCK 0x000004a0
-#define TI_FPREGS	0x000004c0
+#define TI_FPREGS	0x00000500
 
 /* We embed this in the uppermost byte of thread_info->flags */
 #define FAULT_CODE_WRITE	0x01	/* Write access, implies D-TLB		*/
diff -urN linux-2.5.65-bk1/include/asm-sparc64/timer.h linux-2.5.65-bk2/include/asm-sparc64/timer.h
--- linux-2.5.65-bk1/include/asm-sparc64/timer.h	Mon Mar 17 13:43:41 2003
+++ linux-2.5.65-bk2/include/asm-sparc64/timer.h	Mon Mar 31 12:39:51 2003
@@ -50,6 +50,17 @@
  */
 #define SUN5_HZ_TO_LIMIT(__hz)  (1000000/(__hz))
 
+struct sparc64_tick_ops {
+	void (*init_tick)(unsigned long);
+	unsigned long (*get_tick)(void);
+	unsigned long (*get_compare)(void);
+	unsigned long (*add_tick)(unsigned long, unsigned long);
+	unsigned long (*add_compare)(unsigned long);
+	unsigned long softint_mask;
+};
+
+extern struct sparc64_tick_ops *tick_ops;
+
 #ifdef CONFIG_SMP
 extern unsigned long timer_tick_offset;
 extern void timer_tick_interrupt(struct pt_regs *);
diff -urN linux-2.5.65-bk1/include/linux/i2c.h linux-2.5.65-bk2/include/linux/i2c.h
--- linux-2.5.65-bk1/include/linux/i2c.h	Mon Mar 17 13:43:44 2003
+++ linux-2.5.65-bk2/include/linux/i2c.h	Mon Mar 31 12:39:51 2003
@@ -143,7 +143,10 @@
 	 * with the device.
 	 */
 	int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
+
+	struct device_driver driver;
 };
+#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
 extern struct bus_type i2c_bus_type;
 
diff -urN linux-2.5.65-bk1/include/linux/ide.h linux-2.5.65-bk2/include/linux/ide.h
--- linux-2.5.65-bk1/include/linux/ide.h	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/include/linux/ide.h	Mon Mar 31 12:39:51 2003
@@ -341,10 +341,7 @@
 #include <asm/ide.h>
 
 /* Currently only m68k, apus and m8xx need it */
-#ifdef IDE_ARCH_ACK_INTR
-extern int ide_irq_lock;
-# define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
-#else
+#ifndef IDE_ARCH_ACK_INTR
 # define ide_ack_intr(hwif) (1)
 #endif
 
diff -urN linux-2.5.65-bk1/include/linux/in6.h linux-2.5.65-bk2/include/linux/in6.h
--- linux-2.5.65-bk1/include/linux/in6.h	Mon Mar 17 13:44:11 2003
+++ linux-2.5.65-bk2/include/linux/in6.h	Mon Mar 31 12:39:51 2003
@@ -65,6 +65,8 @@
 	int		ipv6mr_ifindex;
 };
 
+#define ipv6mr_acaddr	ipv6mr_multiaddr
+
 struct in6_flowlabel_req
 {
 	struct in6_addr	flr_dst;
@@ -166,6 +168,8 @@
 #define IPV6_MTU		24
 #define IPV6_RECVERR		25
 #define IPV6_V6ONLY		26
+#define IPV6_JOIN_ANYCAST	27
+#define IPV6_LEAVE_ANYCAST	28
 
 /* IPV6_MTU_DISCOVER values */
 #define IPV6_PMTUDISC_DONT		0
diff -urN linux-2.5.65-bk1/include/linux/ip.h linux-2.5.65-bk2/include/linux/ip.h
--- linux-2.5.65-bk1/include/linux/ip.h	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/include/linux/ip.h	Mon Mar 31 12:39:51 2003
@@ -18,8 +18,6 @@
 #define _LINUX_IP_H
 #include <asm/byteorder.h>
 
-/* SOL_IP socket options */
-
 #define IPTOS_TOS_MASK		0x1E
 #define IPTOS_TOS(tos)		((tos)&IPTOS_TOS_MASK)
 #define	IPTOS_LOWDELAY		0x10
@@ -67,14 +65,6 @@
 #define MAXTTL		255
 #define IPDEFTTL	64
 
-/* struct timestamp, struct route and MAX_ROUTES are removed.
-
-   REASONS: it is clear that nobody used them because:
-   - MAX_ROUTES value was wrong.
-   - "struct route" was wrong.
-   - "struct timestamp" had fatally misaligned bitfields and was completely unusable.
- */
-
 #define IPOPT_OPTVAL 0
 #define IPOPT_OLEN   1
 #define IPOPT_OFFSET 2
diff -urN linux-2.5.65-bk1/include/linux/ipv6.h linux-2.5.65-bk2/include/linux/ipv6.h
--- linux-2.5.65-bk1/include/linux/ipv6.h	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/include/linux/ipv6.h	Mon Mar 31 12:39:51 2003
@@ -172,6 +172,7 @@
 				ipv6only:1;
 
 	struct ipv6_mc_socklist	*ipv6_mc_list;
+	struct ipv6_ac_socklist	*ipv6_ac_list;
 	struct ipv6_fl_socklist *ipv6_fl_list;
 	__u32			dst_cookie;
 
diff -urN linux-2.5.65-bk1/include/linux/netdevice.h linux-2.5.65-bk2/include/linux/netdevice.h
--- linux-2.5.65-bk1/include/linux/netdevice.h	Mon Mar 17 13:44:45 2003
+++ linux-2.5.65-bk2/include/linux/netdevice.h	Mon Mar 31 12:39:51 2003
@@ -90,6 +90,11 @@
 #define MAX_HEADER (LL_MAX_HEADER + 48)
 #endif
 
+/* Reserve 16byte aligned hard_header_len, but at least 16.
+ * Alternative is: dev->hard_header_len ? (dev->hard_header_len + 15)&~15 : 0
+ */
+#define LL_RESERVED_SPACE(dev) (((dev)->hard_header_len&~15) + 16)
+
 /*
  *	Network device statistics. Akin to the 2.0 ether stats but
  *	with byte counters.
@@ -360,7 +365,6 @@
 #define NETIF_F_IP_CSUM		2	/* Can checksum only TCP/UDP over IPv4. */
 #define NETIF_F_NO_CSUM		4	/* Does not require checksum. F.e. loopack. */
 #define NETIF_F_HW_CSUM		8	/* Can checksum all the packets. */
-#define NETIF_F_DYNALLOC	16	/* Self-dectructable device. */
 #define NETIF_F_HIGHDMA		32	/* Can DMA to high memory. */
 #define NETIF_F_FRAGLIST	64	/* Scatter/gather IO. */
 #define NETIF_F_HW_VLAN_TX	128	/* Transmit VLAN hw acceleration */
@@ -469,6 +473,10 @@
 extern void		dev_add_pack(struct packet_type *pt);
 extern void		dev_remove_pack(struct packet_type *pt);
 extern int		dev_get(const char *name);
+extern struct net_device	*dev_get_by_flags(unsigned short flags,
+						  unsigned short mask);
+extern struct net_device	*__dev_get_by_flags(unsigned short flags,
+						    unsigned short mask);
 extern struct net_device	*dev_get_by_name(const char *name);
 extern struct net_device	*__dev_get_by_name(const char *name);
 extern struct net_device	*dev_alloc(const char *name, int *err);
diff -urN linux-2.5.65-bk1/include/linux/netfilter_ipv6/ip6_tables.h linux-2.5.65-bk2/include/linux/netfilter_ipv6/ip6_tables.h
--- linux-2.5.65-bk1/include/linux/netfilter_ipv6/ip6_tables.h	Mon Mar 17 13:44:46 2003
+++ linux-2.5.65-bk2/include/linux/netfilter_ipv6/ip6_tables.h	Mon Mar 31 12:39:51 2003
@@ -449,6 +449,9 @@
 				  struct ip6t_table *table,
 				  void *userdata);
 
+/* Check for an extension */
+extern int ip6t_ext_hdr(u8 nexthdr);
+
 #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1))
 
 #endif /*__KERNEL__*/
diff -urN linux-2.5.65-bk1/include/linux/rtc.h linux-2.5.65-bk2/include/linux/rtc.h
--- linux-2.5.65-bk1/include/linux/rtc.h	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/include/linux/rtc.h	Mon Mar 31 12:39:51 2003
@@ -63,7 +63,7 @@
 };
 
 /*
- * ioctl calls that are permitted to the /dev/rtc interface, if 
+ * ioctl calls that are permitted to the /dev/rtc interface, if
  * any of the RTC drivers are enabled.
  */
 
@@ -87,6 +87,7 @@
 
 #define RTC_WKALM_SET	_IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
 #define RTC_WKALM_RD	_IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
+
 #define RTC_PLL_GET	_IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
 #define RTC_PLL_SET	_IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
 
diff -urN linux-2.5.65-bk1/include/linux/serialP.h linux-2.5.65-bk2/include/linux/serialP.h
--- linux-2.5.65-bk1/include/linux/serialP.h	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/include/linux/serialP.h	Mon Mar 31 12:39:51 2003
@@ -22,6 +22,7 @@
 #include <linux/config.h>
 #include <linux/termios.h>
 #include <linux/workqueue.h>
+#include <linux/interrupt.h>
 #include <linux/circ_buf.h>
 #include <linux/wait.h>
 #if (LINUX_VERSION_CODE < 0x020300)
@@ -87,6 +88,7 @@
 	u16			iomem_reg_shift;
 	int			io_type;
 	struct work_struct			work;
+	struct tasklet_struct	tlet;
 #ifdef DECLARE_WAITQUEUE
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
diff -urN linux-2.5.65-bk1/include/linux/skbuff.h linux-2.5.65-bk2/include/linux/skbuff.h
--- linux-2.5.65-bk1/include/linux/skbuff.h	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/include/linux/skbuff.h	Mon Mar 31 12:39:51 2003
@@ -226,7 +226,7 @@
 	unsigned int		len,
 				data_len,
 				csum;
-	unsigned char		__unused,
+	unsigned char		local_df,
 				cloned,
 				pkt_type,
 				ip_summed;
diff -urN linux-2.5.65-bk1/include/linux/tcp.h linux-2.5.65-bk2/include/linux/tcp.h
--- linux-2.5.65-bk1/include/linux/tcp.h	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/include/linux/tcp.h	Mon Mar 31 12:39:51 2003
@@ -245,6 +245,7 @@
 	__u16	mss_cache_std;	/* Like mss_cache, but without TSO */
 	__u16	mss_clamp;	/* Maximal mss, negotiated at connection setup */
 	__u16	ext_header_len;	/* Network protocol overhead (IP/IPv6 options) */
+	__u16	ext2_header_len;/* Options depending on route */
 	__u8	ca_state;	/* State of fast-retransmit machine 	*/
 	__u8	retransmits;	/* Number of unrecovered RTO timeouts.	*/
 
diff -urN linux-2.5.65-bk1/include/net/addrconf.h linux-2.5.65-bk2/include/net/addrconf.h
--- linux-2.5.65-bk1/include/net/addrconf.h	Mon Mar 17 13:44:38 2003
+++ linux-2.5.65-bk2/include/net/addrconf.h	Mon Mar 31 12:39:51 2003
@@ -63,7 +63,15 @@
 extern int			ipv6_get_saddr(struct dst_entry *dst, 
 					       struct in6_addr *daddr,
 					       struct in6_addr *saddr);
+extern int			ipv6_dev_get_saddr(struct net_device *dev, 
+					       struct in6_addr *daddr,
+					       struct in6_addr *saddr,
+					       int onlink);
 extern int			ipv6_get_lladdr(struct net_device *dev, struct in6_addr *);
+extern void			addrconf_join_solict(struct net_device *dev,
+					struct in6_addr *addr);
+extern void			addrconf_leave_solict(struct net_device *dev,
+					struct in6_addr *addr);
 
 /*
  *	multicast prototypes (mcast.c)
@@ -93,6 +101,26 @@
 extern void			addrconf_prefix_rcv(struct net_device *dev,
 						    u8 *opt, int len);
 
+/*
+ *	anycast prototypes (anycast.c)
+ */
+extern int			ipv6_sock_ac_join(struct sock *sk, 
+						  int ifindex, 
+						  struct in6_addr *addr);
+extern int			ipv6_sock_ac_drop(struct sock *sk,
+						  int ifindex, 
+						  struct in6_addr *addr);
+extern void			ipv6_sock_ac_close(struct sock *sk);
+extern int			inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex);
+
+extern int			ipv6_dev_ac_inc(struct net_device *dev,
+						struct in6_addr *addr);
+extern int			ipv6_dev_ac_dec(struct net_device *dev,
+						struct in6_addr *addr);
+extern int			ipv6_chk_acast_addr(struct net_device *dev,
+						struct in6_addr *addr);
+
+
 /* Device notifier */
 extern int register_inet6addr_notifier(struct notifier_block *nb);
 extern int unregister_inet6addr_notifier(struct notifier_block *nb);
diff -urN linux-2.5.65-bk1/include/net/dst.h linux-2.5.65-bk2/include/net/dst.h
--- linux-2.5.65-bk1/include/net/dst.h	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/include/net/dst.h	Mon Mar 31 12:39:51 2003
@@ -50,7 +50,8 @@
 	unsigned long		lastuse;
 	unsigned long		expires;
 
-	unsigned		header_len;	/* more space at head required */
+	unsigned short		header_len;	/* more space at head required */
+	unsigned short		trailer_len;	/* space to reserve at tail */
 
 	u32			metrics[RTAX_MAX];
 	struct dst_entry	*path;
diff -urN linux-2.5.65-bk1/include/net/if_inet6.h linux-2.5.65-bk2/include/net/if_inet6.h
--- linux-2.5.65-bk1/include/net/if_inet6.h	Mon Mar 17 13:44:47 2003
+++ linux-2.5.65-bk2/include/net/if_inet6.h	Mon Mar 31 12:39:51 2003
@@ -75,6 +75,25 @@
 	spinlock_t		mca_lock;
 };
 
+/* Anycast stuff */
+
+struct ipv6_ac_socklist
+{
+	struct in6_addr		acl_addr;
+	int			acl_ifindex;
+	struct ipv6_ac_socklist *acl_next;
+};
+
+struct ifacaddr6
+{
+	struct in6_addr		aca_addr;
+	struct inet6_dev	*aca_idev;
+	struct ifacaddr6	*aca_next;
+	int			aca_users;
+	atomic_t		aca_refcnt;
+	spinlock_t		aca_lock;
+};
+
 #define	IFA_HOST	IPV6_ADDR_LOOPBACK
 #define	IFA_LINK	IPV6_ADDR_LINKLOCAL
 #define	IFA_SITE	IPV6_ADDR_SITELOCAL
@@ -108,6 +127,7 @@
 
 	struct inet6_ifaddr	*addr_list;
 	struct ifmcaddr6	*mc_list;
+	struct ifacaddr6	*ac_list;
 	rwlock_t		lock;
 	atomic_t		refcnt;
 	__u32			if_flags;
diff -urN linux-2.5.65-bk1/include/net/sctp/command.h linux-2.5.65-bk2/include/net/sctp/command.h
--- linux-2.5.65-bk1/include/net/sctp/command.h	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/include/net/sctp/command.h	Mon Mar 31 12:39:51 2003
@@ -110,13 +110,13 @@
 	sctp_event_timeout_t to;
 	sctp_counter_t counter;
 	void *ptr;
-	sctp_chunk_t *chunk;
-	sctp_association_t *asoc;
+	struct sctp_chunk *chunk;
+	struct sctp_association *asoc;
 	struct sctp_transport *transport;
-	sctp_bind_addr_t  *bp;
+	struct sctp_bind_addr *bp;
 	sctp_init_chunk_t *init;
 	struct sctp_ulpevent *ulpevent;
-	sctp_packet_t *packet;
+	struct sctp_packet *packet;
 	sctp_sackhdr_t *sackh;
 } sctp_arg_t;
 
@@ -158,13 +158,13 @@
 SCTP_ARG_CONSTRUCTOR(COUNTER,	sctp_counter_t, counter)
 SCTP_ARG_CONSTRUCTOR(TO,	sctp_event_timeout_t, to)
 SCTP_ARG_CONSTRUCTOR(PTR,	void *, ptr)
-SCTP_ARG_CONSTRUCTOR(CHUNK,	sctp_chunk_t *, chunk)
-SCTP_ARG_CONSTRUCTOR(ASOC,	sctp_association_t *, asoc)
+SCTP_ARG_CONSTRUCTOR(CHUNK,	struct sctp_chunk *, chunk)
+SCTP_ARG_CONSTRUCTOR(ASOC,	struct sctp_association *, asoc)
 SCTP_ARG_CONSTRUCTOR(TRANSPORT,	struct sctp_transport *, transport)
-SCTP_ARG_CONSTRUCTOR(BA,	sctp_bind_addr_t *, bp)
+SCTP_ARG_CONSTRUCTOR(BA,	struct sctp_bind_addr *, bp)
 SCTP_ARG_CONSTRUCTOR(PEER_INIT,	sctp_init_chunk_t *, init)
 SCTP_ARG_CONSTRUCTOR(ULPEVENT,  struct sctp_ulpevent *, ulpevent)
-SCTP_ARG_CONSTRUCTOR(PACKET,	sctp_packet_t *, packet)
+SCTP_ARG_CONSTRUCTOR(PACKET,	struct sctp_packet *, packet)
 SCTP_ARG_CONSTRUCTOR(SACKH,	sctp_sackhdr_t *, sackh)
 
 typedef struct {
diff -urN linux-2.5.65-bk1/include/net/sctp/constants.h linux-2.5.65-bk2/include/net/sctp/constants.h
--- linux-2.5.65-bk1/include/net/sctp/constants.h	Mon Mar 17 13:44:02 2003
+++ linux-2.5.65-bk2/include/net/sctp/constants.h	Mon Mar 31 12:39:51 2003
@@ -210,14 +210,19 @@
 
 /* These are values for sk->state.
  * For a UDP-style SCTP socket, the states are defined as follows
- *   (at this point of time, may change later after more discussions: FIXME)
- * A socket in SCTP_SS_UNCONNECTED state indicates that it is not willing
- * to accept new associations, but it can initiate the creation of new
- * ones.
- * A socket in SCTP_SS_LISTENING state indicates that it is willing to
- * accept new  associations and can initiate the creation of new ones.
- * A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off
- * socket with one association.
+ * - A socket in SCTP_SS_CLOSED state indicates that it is not willing to
+ *   accept new associations, but it can initiate the creation of new ones.
+ * - A socket in SCTP_SS_LISTENING state indicates that it is willing to
+ *   accept new  associations and can initiate the creation of new ones.
+ * - A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off
+ *   socket with one association.
+ * For a TCP-style SCTP socket, the states are defined as follows
+ * - A socket in SCTP_SS_CLOSED state indicates that it is not willing to
+ *   accept new associations, but it can initiate the creation of new ones.
+ * - A socket in SCTP_SS_LISTENING state indicates that it is willing to
+ *   accept new associations, but cannot initiate the creation of new ones.
+ * - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single 
+ *   association in ESTABLISHED state.
  */
 typedef enum {
 	SCTP_SS_CLOSED         = TCP_CLOSE,
@@ -345,6 +350,7 @@
 	SCTP_XMIT_PMTU_FULL,
 	SCTP_XMIT_RWND_FULL,
 	SCTP_XMIT_MUST_FRAG,
+	SCTP_XMIT_NAGLE_DELAY,
 } sctp_xmit_t;
 
 /* These are the commands for manipulating transports.  */
diff -urN linux-2.5.65-bk1/include/net/sctp/sctp.h linux-2.5.65-bk2/include/net/sctp/sctp.h
--- linux-2.5.65-bk1/include/net/sctp/sctp.h	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/include/net/sctp/sctp.h	Mon Mar 31 12:39:51 2003
@@ -121,9 +121,10 @@
 /*
  * sctp_protocol.c
  */
-extern sctp_protocol_t sctp_proto;
+extern struct sctp_protocol sctp_proto;
 extern struct sock *sctp_get_ctl_sock(void);
-extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *,
+extern int sctp_copy_local_addr_list(struct sctp_protocol  *, 
+				     struct sctp_bind_addr *,
 				     sctp_scope_t, int priority, int flags);
 extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
 extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
@@ -312,30 +313,21 @@
 #endif
 
 
+/* Size of Supported Address Parameter for 'x' address types. */
+#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16))
+
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 
 extern int sctp_v6_init(void);
 extern void sctp_v6_exit(void);
-
 static inline int sctp_ipv6_addr_type(const struct in6_addr *addr)
 {
 	return ipv6_addr_type((struct in6_addr*) addr);
 }
 
-#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 2 * sizeof(__u16))
-
-/* Note: These V6 macros are obsolescent.  */
-/* Use this macro to enclose code fragments which are V6-dependent. */
-#define SCTP_V6(m...)	m
-#define SCTP_V6_SUPPORT 1
-
 #else /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 
 #define sctp_ipv6_addr_type(a) 0
-#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 1 * sizeof(__u16))
-#define SCTP_V6(m...) /* Do nothing. */
-#undef SCTP_V6_SUPPORT
-
 static inline int sctp_v6_init(void) { return 0; }
 static inline void sctp_v6_exit(void) { return; }
 
@@ -348,25 +340,10 @@
 	return (sctp_assoc_t) asoc;
 }
 
-/* Look up the association by its id.  */
-static inline sctp_association_t *sctp_id2assoc(const struct sock *sk, sctp_assoc_t id)
-{
-	sctp_association_t *asoc = NULL;
 
-	/* First, verify that this is a kernel address. */
-	if (sctp_is_valid_kaddr((unsigned long) id)) {
-		sctp_association_t *temp = (sctp_association_t *) id;
-
-		/* Verify that this _is_ an sctp_association_t
-		 * data structure and if so, that the socket matches.
-		 */
-		if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) &&
-		    (temp->base.sk == sk))
-			asoc = temp;
-	}
+/* Look up the association by its id.  */
+sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id);
 
-	return asoc;
-}
 
 /* A macro to walk a list of skbs.  */
 #define sctp_skb_for_each(pos, head, tmp) \
@@ -494,7 +471,7 @@
 /* Static inline functions. */
 
 /* Return the SCTP protocol structure. */
-static inline sctp_protocol_t *sctp_get_protocol(void)
+static inline struct sctp_protocol *sctp_get_protocol(void)
 {
 	return &sctp_proto;
 }
@@ -523,21 +500,21 @@
 /* This is the hash function for the SCTP port hash table. */
 static inline int sctp_phashfn(__u16 lport)
 {
-	sctp_protocol_t *sctp_proto = sctp_get_protocol();
+	struct sctp_protocol *sctp_proto = sctp_get_protocol();
 	return (lport & (sctp_proto->port_hashsize - 1));
 }
 
 /* This is the hash function for the endpoint hash table. */
 static inline int sctp_ep_hashfn(__u16 lport)
 {
-	sctp_protocol_t *sctp_proto = sctp_get_protocol();
+	struct sctp_protocol *sctp_proto = sctp_get_protocol();
 	return (lport & (sctp_proto->ep_hashsize - 1));
 }
 
 /* This is the hash function for the association hash table. */
 static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
 {
-	sctp_protocol_t *sctp_proto = sctp_get_protocol();
+	struct sctp_protocol *sctp_proto = sctp_get_protocol();
 	int h = (lport << 16) + rport;
 	h ^= h>>8;
 	return (h & (sctp_proto->assoc_hashsize - 1));
@@ -549,7 +526,7 @@
  */
 static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag)
 {
-	sctp_protocol_t *sctp_proto = sctp_get_protocol();
+	struct sctp_protocol *sctp_proto = sctp_get_protocol();
 	int h = (lport << 16) + rport;
 	h ^= vtag;
 	return (h & (sctp_proto->assoc_hashsize-1));
diff -urN linux-2.5.65-bk1/include/net/sctp/sm.h linux-2.5.65-bk2/include/net/sctp/sm.h
--- linux-2.5.65-bk1/include/net/sctp/sm.h	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/include/net/sctp/sm.h	Mon Mar 31 12:39:51 2003
@@ -3,40 +3,40 @@
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001-2002 International Business Machines Corp.
- * 
+ *
  * This file is part of the SCTP kernel reference Implementation
- * 
+ *
  * This file is part of the implementation of the add-IP extension,
  * based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001,
  * for the SCTP kernel reference Implementation.
- * 
+ *
  * These are definitions needed by the state machine.
- * 
- * The SCTP reference implementation is free software; 
- * you can redistribute it and/or modify it under the terms of 
+ *
+ * The SCTP reference implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
- * 
- * The SCTP reference implementation is distributed in the hope that it 
+ *
+ * The SCTP reference implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  * See the GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with GNU CC; see the file COPYING.  If not, write to
  * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.  
- * 
+ * Boston, MA 02111-1307, USA.
+ *
  * Please send any bug reports or fixes you make to the
  * email addresses:
  *    lksctp developers <lksctp-developers@lists.sourceforge.net>
- * 
+ *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
  *
- * Written or modified by: 
+ * Written or modified by:
  *    La Monte H.P. Yarroll <piggy@acm.org>
  *    Karl Knutson <karl@athena.chicago.il.us>
  *    Xingang Guo <xingang.guo@intel.com>
@@ -313,18 +313,18 @@
 void sctp_generate_heartbeat_event(unsigned long peer);
 
 sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *);
-sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
-				  const sctp_association_t *asoc,
-				  sctp_chunk_t *chunk,
-				  const void *payload,
-				  size_t paylen);
-sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
-				 const sctp_chunk_t *chunk);
-void sctp_ootb_pkt_free(sctp_packet_t *packet);
+struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *,
+				       const struct sctp_association *,
+				       struct sctp_chunk *chunk,
+				       const void *payload,
+				       size_t paylen);
+struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *,
+				      const struct sctp_chunk *);
+void sctp_ootb_pkt_free(struct sctp_packet *);
 
 sctp_cookie_param_t *
-sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *,
-		 const sctp_chunk_t *, int *cookie_len,
+sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *,
+		 const struct sctp_chunk *, int *cookie_len,
 		 const __u8 *, int addrs_len);
 sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *,
 				       const sctp_association_t *,
diff -urN linux-2.5.65-bk1/include/net/sctp/structs.h linux-2.5.65-bk2/include/net/sctp/structs.h
--- linux-2.5.65-bk1/include/net/sctp/structs.h	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/include/net/sctp/structs.h	Mon Mar 31 12:39:51 2003
@@ -86,10 +86,8 @@
 struct sctp_endpoint_common;
 struct sctp_ssnmap;
 
-typedef struct sctp_protocol sctp_protocol_t;
 typedef struct sctp_endpoint sctp_endpoint_t;
 typedef struct sctp_association sctp_association_t;
-typedef struct sctp_packet sctp_packet_t;
 typedef struct sctp_chunk sctp_chunk_t;
 typedef struct sctp_bind_addr sctp_bind_addr_t;
 typedef struct sctp_endpoint_common sctp_endpoint_common_t;
@@ -222,7 +220,7 @@
 	void 		(*get_saddr)	(struct sctp_association *asoc,
 					 struct dst_entry *dst,
 					 union sctp_addr *daddr,
-				 	 union sctp_addr *saddr);	 
+				 	 union sctp_addr *saddr);
 	void            (*copy_addrlist) (struct list_head *,
 					  struct net_device *);
 	void            (*dst_saddr)    (union sctp_addr *saddr,
@@ -262,6 +260,9 @@
 			  const union sctp_addr *,
 			  struct sctp_opt *);
 	int  (*bind_verify) (struct sctp_opt *, union sctp_addr *);
+	int  (*supported_addrs)(const struct sctp_opt *, __u16 *);
+	struct sock *(*create_accept_sk) (struct sock *sk,
+					  struct sctp_association *asoc);
 	struct sctp_af *af;
 };
 
@@ -366,8 +367,6 @@
 	sctp_cookie_t c;
 } sctp_signed_cookie_t;
 
-
-
 /* This is another convenience type to allocate memory for address
  * params for the maximum size and pass such structures around
  * internally.
@@ -604,26 +603,26 @@
 
 typedef int (sctp_outq_thandler_t)(struct sctp_outq *, void *);
 typedef int (sctp_outq_ehandler_t)(struct sctp_outq *);
-typedef sctp_packet_t *(sctp_outq_ohandler_init_t)
-	(sctp_packet_t *,
+typedef struct sctp_packet *(sctp_outq_ohandler_init_t)
+	(struct sctp_packet *,
          struct sctp_transport *,
          __u16 sport,
          __u16 dport);
-typedef sctp_packet_t *(sctp_outq_ohandler_config_t)
-        (sctp_packet_t *,
+typedef struct sctp_packet *(sctp_outq_ohandler_config_t)
+        (struct sctp_packet *,
 	 __u32 vtag,
 	 int ecn_capable,
 	 sctp_packet_phandler_t *get_prepend_chunk);
-typedef sctp_xmit_t (sctp_outq_ohandler_t)(sctp_packet_t *,
+typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *,
                                                sctp_chunk_t *);
-typedef int (sctp_outq_ohandler_force_t)(sctp_packet_t *);
+typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *);
 
 sctp_outq_ohandler_init_t    sctp_packet_init;
 sctp_outq_ohandler_config_t  sctp_packet_config;
 sctp_outq_ohandler_t         sctp_packet_append_chunk;
 sctp_outq_ohandler_t         sctp_packet_transmit_chunk;
 sctp_outq_ohandler_force_t   sctp_packet_transmit;
-void sctp_packet_free(sctp_packet_t *);
+void sctp_packet_free(struct sctp_packet *);
 
 
 /* This represents a remote transport address.
@@ -789,7 +788,7 @@
 	struct list_head transmitted;
 
 	/* We build bundle-able packets for this transport here.  */
-	sctp_packet_t packet;
+	struct sctp_packet packet;
 
 	/* This is the list of transports that have chunks to send.  */
 	struct list_head send_ready;
@@ -865,12 +864,11 @@
 struct sctp_outq {
 	sctp_association_t *asoc;
 
-	/* BUG: This really should be an array of streams.
-	 * This really holds a list of chunks (one stream).
-	 * FIXME: If true, why so?
-	 */
+	/* Data pending that has never been transmitted.  */
 	struct sk_buff_head out;
 
+	unsigned out_qlen;	/* Total length of queued data chunks. */
+
 	/* These are control chunks we want to send.  */
 	struct sk_buff_head control;
 
@@ -885,7 +883,7 @@
 	struct list_head retransmit;
 
 	/* Call these functions to send chunks down to the next lower
-	 * layer.  This is always SCTP_packet, but we separate the two
+	 * layer.  This is always sctp_packet, but we separate the two
 	 * structures to make testing simpler.
 	 */
 	sctp_outq_ohandler_init_t	*init_output;
@@ -1098,8 +1096,9 @@
 }
 
 /* These are function signatures for manipulating endpoints.  */
-sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *, struct sock *, int);
-sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *, sctp_protocol_t *,
+sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *, struct sock *, int);
+sctp_endpoint_t *sctp_endpoint_init(struct sctp_endpoint *,
+				    struct sctp_protocol *,
 				    struct sock *, int priority);
 void sctp_endpoint_free(sctp_endpoint_t *);
 void sctp_endpoint_put(sctp_endpoint_t *);
@@ -1111,7 +1110,6 @@
 int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *);
 sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *,
 					const union sctp_addr *);
-
 int sctp_has_association(const union sctp_addr *laddr,
 			 const union sctp_addr *paddr);
 
@@ -1587,7 +1585,7 @@
 struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *,
 				     const union sctp_addr *address,
 				     const int priority);
-void sctp_assoc_control_transport(sctp_association_t *,
+void sctp_assoc_control_transport(struct sctp_association *,
 				  struct sctp_transport *,
 				  sctp_transport_cmd_t, sctp_sn_error_t);
 struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *, __u32);
@@ -1597,14 +1595,14 @@
 void sctp_assoc_migrate(sctp_association_t *, struct sock *);
 void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src);
 
-__u32 __sctp_association_get_next_tsn(sctp_association_t *);
-__u32 __sctp_association_get_tsn_block(sctp_association_t *, int);
-__u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid);
-
-void sctp_assoc_sync_pmtu(sctp_association_t *);
-void sctp_assoc_rwnd_increase(sctp_association_t *, int);
-void sctp_assoc_rwnd_decrease(sctp_association_t *, int);
+__u32 sctp_association_get_next_tsn(struct sctp_association *);
+__u32 sctp_association_get_tsn_block(struct sctp_association *, int);
 
+void sctp_assoc_sync_pmtu(struct sctp_association *);
+void sctp_assoc_rwnd_increase(struct sctp_association *, int);
+void sctp_assoc_rwnd_decrease(struct sctp_association *, int);
+void sctp_assoc_set_primary(struct sctp_association *,
+			    struct sctp_transport *);
 int sctp_assoc_set_bind_addr_from_ep(sctp_association_t *, int);
 int sctp_assoc_set_bind_addr_from_cookie(sctp_association_t *,
 					 sctp_cookie_t *, int);
diff -urN linux-2.5.65-bk1/include/net/sctp/user.h linux-2.5.65-bk2/include/net/sctp/user.h
--- linux-2.5.65-bk1/include/net/sctp/user.h	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/include/net/sctp/user.h	Mon Mar 31 12:39:51 2003
@@ -108,6 +108,8 @@
 #define SCTP_GET_LOCAL_ADDRS_NUM	SCTP_GET_LOCAL_ADDRS_NUM
 	SCTP_GET_LOCAL_ADDRS, 	/* Get all local addresss. */
 #define SCTP_GET_LOCAL_ADDRS	SCTP_GET_LOCAL_ADDRS
+	SCTP_NODELAY, 	/* Get/set nodelay option. */
+#define SCTP_NODELAY	SCTP_NODELAY
 };
 
 
diff -urN linux-2.5.65-bk1/include/net/tcp.h linux-2.5.65-bk2/include/net/tcp.h
--- linux-2.5.65-bk1/include/net/tcp.h	Mon Mar 17 13:43:41 2003
+++ linux-2.5.65-bk2/include/net/tcp.h	Mon Mar 31 12:39:51 2003
@@ -927,7 +927,8 @@
 
 	if (dst) {
 		u32 mtu = dst_pmtu(dst);
-		if (mtu != tp->pmtu_cookie)
+		if (mtu != tp->pmtu_cookie ||
+		    tp->ext2_header_len != dst->header_len)
 			mss_now = tcp_sync_mss(sk, mtu);
 	}
 	if (tp->eff_sacks)
diff -urN linux-2.5.65-bk1/include/net/xfrm.h linux-2.5.65-bk2/include/net/xfrm.h
--- linux-2.5.65-bk1/include/net/xfrm.h	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/include/net/xfrm.h	Mon Mar 31 12:39:51 2003
@@ -107,6 +107,7 @@
 		u16		family;
 		xfrm_address_t	saddr;
 		int		header_len;
+		int		trailer_len;
 	} props;
 
 	struct xfrm_lifetime_cfg lft;
@@ -255,6 +256,11 @@
 		__xfrm_state_destroy(x);
 }
 
+static inline void xfrm_state_hold(struct xfrm_state *x)
+{
+	atomic_inc(&x->refcnt);
+}
+
 static inline int
 xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
 {
@@ -353,7 +359,7 @@
 static inline int xfrm_sk_clone_policy(struct sock *sk)
 {
 	if (unlikely(sk->policy[0] || sk->policy[1]))
-		return xfrm_sk_clone_policy(sk);
+		return __xfrm_sk_clone_policy(sk);
 	return 0;
 }
 
diff -urN linux-2.5.65-bk1/include/sound/ac97_codec.h linux-2.5.65-bk2/include/sound/ac97_codec.h
--- linux-2.5.65-bk1/include/sound/ac97_codec.h	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/include/sound/ac97_codec.h	Mon Mar 31 12:39:51 2003
@@ -156,12 +156,30 @@
 /* extended modem ID bit defines */
 #define AC97_MEI_LINE1		0x0001	/* Line1 present */
 #define AC97_MEI_LINE2		0x0002	/* Line2 present */
-#define AC97_MEI_HEADSET	0x0004	/* Headset present */
+#define AC97_MEI_HANDSET	0x0004	/* Handset present */
 #define AC97_MEI_CID1		0x0008	/* caller ID decode for Line1 is supported */
 #define AC97_MEI_CID2		0x0010	/* caller ID decode for Line2 is supported */
 #define AC97_MEI_ADDR_MASK	0xc000	/* physical codec ID (address) */
 #define AC97_MEI_ADDR_SHIFT	14
 
+/* extended modem status and control bit defines */
+#define AC97_MEA_GPIO		0x0001	/* GPIO is ready (ro) */
+#define AC97_MEA_MREF		0x0002	/* Vref is up to nominal level (ro) */
+#define AC97_MEA_ADC1		0x0004	/* ADC1 operational (ro) */
+#define AC97_MEA_DAC1		0x0008	/* DAC1 operational (ro) */
+#define AC97_MEA_ADC2		0x0010	/* ADC2 operational (ro) */
+#define AC97_MEA_DAC2		0x0020	/* DAC2 operational (ro) */
+#define AC97_MEA_HADC		0x0040	/* HADC operational (ro) */
+#define AC97_MEA_HDAC		0x0080	/* HDAC operational (ro) */
+#define AC97_MEA_PRA		0x0100	/* GPIO power down (high) */
+#define AC97_MEA_PRB		0x0200	/* reserved */
+#define AC97_MEA_PRC		0x0400	/* ADC1 power down (high) */
+#define AC97_MEA_PRD		0x0800	/* DAC1 power down (high) */
+#define AC97_MEA_PRE		0x1000	/* ADC2 power down (high) */
+#define AC97_MEA_PRF		0x2000	/* DAC2 power down (high) */
+#define AC97_MEA_PRG		0x4000	/* HADC power down (high) */
+#define AC97_MEA_PRH		0x8000	/* HDAC power down (high) */
+
 /* specific - SigmaTel */
 #define AC97_SIGMATEL_ANALOG	0x6c	/* Analog Special */
 #define AC97_SIGMATEL_DAC2INVERT 0x6e
@@ -268,6 +286,14 @@
 };
 
 /* conditions */
+static inline int ac97_is_audio(ac97_t * ac97)
+{
+	return (ac97->scaps & AC97_SCAP_AUDIO);
+}
+static inline int ac97_is_modem(ac97_t * ac97)
+{
+	return (ac97->scaps & AC97_SCAP_MODEM);
+}
 static inline int ac97_is_rev22(ac97_t * ac97)
 {
 	return (ac97->ext_id & AC97_EI_REV_MASK) == AC97_EI_REV_22;
@@ -278,7 +304,8 @@
 }
 
 /* functions */
-int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97);
+int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97);	/* create mixer controls */
+int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97);	/* create modem controls */
 
 void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value);
 unsigned short snd_ac97_read(ac97_t *ac97, unsigned short reg);
@@ -296,6 +323,7 @@
 struct ac97_quirk {
 	unsigned short vendor;
 	unsigned short device;
+	const char *name;
 	int type;
 };
 
diff -urN linux-2.5.65-bk1/include/sound/asound.h linux-2.5.65-bk2/include/sound/asound.h
--- linux-2.5.65-bk1/include/sound/asound.h	Mon Mar 17 13:44:18 2003
+++ linux-2.5.65-bk2/include/sound/asound.h	Mon Mar 31 12:39:51 2003
@@ -1,6 +1,6 @@
 /*
  *  Advanced Linux Sound Architecture - ALSA - Driver
- *  Copyright (c) 1994-2000 by Jaroslav Kysela <perex@suse.cz>,
+ *  Copyright (c) 1994-2003 by Jaroslav Kysela <perex@suse.cz>,
  *                             Abramo Bagnara <abramo@alsa-project.org>
  *
  *
@@ -93,7 +93,7 @@
  *                                                                          *
  ****************************************************************************/
 
-#define SNDRV_HWDEP_VERSION		SNDRV_PROTOCOL_VERSION(1, 0, 0)
+#define SNDRV_HWDEP_VERSION		SNDRV_PROTOCOL_VERSION(1, 0, 1)
 
 enum sndrv_hwdep_iface {
 	SNDRV_HWDEP_IFACE_OPL2 = 0,
@@ -104,9 +104,10 @@
 	SNDRV_HWDEP_IFACE_YSS225,	/* Yamaha FX processor */
 	SNDRV_HWDEP_IFACE_ICS2115,	/* Wavetable synth */
 	SNDRV_HWDEP_IFACE_SSCAPE,	/* Ensoniq SoundScape ISA card (MC68EC000) */
+	SNDRV_HWDEP_IFACE_VX,		/* Digigram VX cards */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SSCAPE,
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_VX,
 };
 
 struct sndrv_hwdep_info {
@@ -118,9 +119,29 @@
 	unsigned char reserved[64];	/* reserved for future */
 };
 
+/* generic DSP loader */
+struct sndrv_hwdep_dsp_status {
+	unsigned int version;		/* R: driver-specific version */
+	unsigned char id[32];		/* R: driver-specific ID string */
+	unsigned int num_dsps;		/* R: number of DSP images to transfer */
+	unsigned int dsp_loaded;	/* R: bit flags indicating the loaded DSPs */
+	unsigned int chip_ready;	/* R: 1 = initialization finished */
+	unsigned char reserved[16];	/* reserved for future use */
+};
+
+struct sndrv_hwdep_dsp_image {
+	unsigned int index;		/* W: DSP index */
+	unsigned char name[64];		/* W: ID (e.g. file name) */
+	unsigned char *image;		/* W: binary image */
+	size_t length;			/* W: size of image in bytes */
+	unsigned long driver_data;	/* W: driver-specific data */
+};
+
 enum {
 	SNDRV_HWDEP_IOCTL_PVERSION = _IOR ('H', 0x00, int),
 	SNDRV_HWDEP_IOCTL_INFO = _IOR ('H', 0x01, struct sndrv_hwdep_info),
+	SNDRV_HWDEP_IOCTL_DSP_STATUS = _IOR('H', 0x02, struct sndrv_hwdep_dsp_status),
+	SNDRV_HWDEP_IOCTL_DSP_LOAD   = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image)
 };
 
 /*****************************************************************************
@@ -129,7 +150,7 @@
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 3)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 5)
 
 typedef unsigned long sndrv_pcm_uframes_t;
 typedef long sndrv_pcm_sframes_t;
@@ -377,8 +398,8 @@
 
 struct sndrv_pcm_status {
 	enum sndrv_pcm_state state;	/* stream state */
-	struct timeval trigger_tstamp;	/* time when stream was started/stopped/paused */
-	struct timeval tstamp;		/* reference timestamp */
+	struct timespec trigger_tstamp;	/* time when stream was started/stopped/paused */
+	struct timespec tstamp;		/* reference timestamp */
 	sndrv_pcm_uframes_t appl_ptr;	/* appl ptr */
 	sndrv_pcm_uframes_t hw_ptr;	/* hw ptr */
 	sndrv_pcm_sframes_t delay;	/* current delay in frames */
@@ -393,7 +414,7 @@
 	enum sndrv_pcm_state state;	/* RO: state - SNDRV_PCM_STATE_XXXX */
 	int pad1;			/* Needed for 64 bit alignment */
 	sndrv_pcm_uframes_t hw_ptr;	/* RO: hw ptr (0...boundary-1) */
-	struct timeval tstamp;		/* Timestamp */
+	struct timespec tstamp;		/* Timestamp */
 	enum sndrv_pcm_state suspended_state; /* RO: suspended stream state */
 };
 
@@ -417,6 +438,7 @@
 enum {
 	SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int),
 	SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct sndrv_pcm_info),
+	SNDRV_PCM_IOCTL_TSTAMP = _IOW('A', 0x02, int),
 	SNDRV_PCM_IOCTL_HW_REFINE = _IOWR('A', 0x10, struct sndrv_pcm_hw_params),
 	SNDRV_PCM_IOCTL_HW_PARAMS = _IOWR('A', 0x11, struct sndrv_pcm_hw_params),
 	SNDRV_PCM_IOCTL_HW_FREE = _IO('A', 0x12),
@@ -434,6 +456,7 @@
 	SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, sndrv_pcm_uframes_t),
 	SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47),
 	SNDRV_PCM_IOCTL_XRUN = _IO('A', 0x48),
+	SNDRV_PCM_IOCTL_FORWARD = _IOW('A', 0x49, sndrv_pcm_uframes_t),
 	SNDRV_PCM_IOCTL_WRITEI_FRAMES = _IOW('A', 0x50, struct sndrv_xferi),
 	SNDRV_PCM_IOCTL_READI_FRAMES = _IOR('A', 0x51, struct sndrv_xferi),
 	SNDRV_PCM_IOCTL_WRITEN_FRAMES = _IOW('A', 0x52, struct sndrv_xfern),
@@ -491,7 +514,7 @@
 
 struct sndrv_rawmidi_status {
 	enum sndrv_rawmidi_stream stream;
-	struct timeval tstamp;		/* Timestamp */
+	struct timespec tstamp;		/* Timestamp */
 	size_t avail;			/* available bytes */
 	size_t xruns;			/* count of overruns since last status (in bytes) */
 	unsigned char reserved[16];	/* reserved for future use */
@@ -510,7 +533,7 @@
  *  Timer section - /dev/snd/timer
  */
 
-#define SNDRV_TIMER_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 0)
+#define SNDRV_TIMER_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 1)
 
 enum sndrv_timer_class {
 	SNDRV_TIMER_CLASS_NONE = -1,
@@ -534,6 +557,9 @@
 #define SNDRV_TIMER_GLOBAL_SYSTEM	0
 #define SNDRV_TIMER_GLOBAL_RTC		1
 
+/* info flags */
+#define SNDRV_TIMER_FLG_SLAVE		(1<<0)	/* cannot be controlled */
+
 struct sndrv_timer_id {
 	enum sndrv_timer_class dev_class;	
 	enum sndrv_timer_slave_class dev_sclass;
@@ -542,36 +568,65 @@
 	int subdevice;
 };
 
+struct sndrv_timer_ginfo {
+	struct sndrv_timer_id tid;	/* requested timer ID */
+	unsigned int flags;		/* timer flags - SNDRV_TIMER_FLG_* */
+	int card;			/* card number */
+	unsigned char id[64];		/* timer identification */
+	unsigned char name[80];		/* timer name */
+	unsigned long reserved0;	/* reserved for future use */
+	unsigned long resolution;	/* average period resolution in ns */
+	unsigned long resolution_min;	/* minimal period resolution in ns */
+	unsigned long resolution_max;	/* maximal period resolution in ns */
+	unsigned int clients;		/* active timer clients */
+	unsigned char reserved[32];
+};
+
+struct sndrv_timer_gparams {
+	struct sndrv_timer_id tid;	/* requested timer ID */
+	unsigned long period_num;	/* requested precise period duration (in seconds) - numerator */
+	unsigned long period_den;	/* requested precise period duration (in seconds) - denominator */
+	unsigned char reserved[32];
+};
+
+struct sndrv_timer_gstatus {
+	struct sndrv_timer_id tid;	/* requested timer ID */
+	unsigned long resolution;	/* current period resolution in ns */
+	unsigned long resolution_num;	/* precise current period resolution (in seconds) - numerator */
+	unsigned long resolution_den;	/* precise current period resolution (in seconds) - denominator */
+	unsigned char reserved[32];
+};
+
 struct sndrv_timer_select {
 	struct sndrv_timer_id id;	/* bind to timer ID */
 	unsigned char reserved[32];	/* reserved */
 };
 
-#define SNDRV_TIMER_FLG_SLAVE		(1<<0)	/* cannot be controlled */
-
 struct sndrv_timer_info {
 	unsigned int flags;		/* timer flags - SNDRV_TIMER_FLG_* */
-	int card;			/* R: card number */
+	int card;			/* card number */
 	unsigned char id[64];		/* timer identificator */
 	unsigned char name[80];		/* timer name */
-	unsigned long ticks;		/* maximum ticks */
-	unsigned long resolution;	/* average resolution */
+	unsigned long reserved0;	/* reserved for future use */
+	unsigned long resolution;	/* average period resolution in ns */
 	unsigned char reserved[64];	/* reserved */
 };
 
-#define SNDRV_TIMER_PSFLG_AUTO		(1<<0)	/* supports auto start */
+#define SNDRV_TIMER_PSFLG_AUTO		(1<<0)	/* auto start, otherwise one-shot */
+#define SNDRV_TIMER_PSFLG_EXCLUSIVE	(1<<1)	/* exclusive use, precise start/stop/pause/continue */
 
 struct sndrv_timer_params {
 	unsigned int flags;		/* flags - SNDRV_MIXER_PSFLG_* */
 	unsigned int ticks;		/* requested resolution in ticks */
 	unsigned int queue_size;	/* total size of queue (32-1024) */
 	unsigned int reserved0;		/* reserved, was: failure locations */
-	unsigned char reserved[64];	/* reserved */
+	unsigned int filter;		/* event filter (bitmask of SNDRV_TIMER_EVENT_*) */
+	unsigned char reserved[60];	/* reserved */
 };
 
 struct sndrv_timer_status {
-	struct timeval tstamp;		/* Timestamp */
-	unsigned int resolution;	/* current resolution */
+	struct timespec tstamp;		/* Timestamp - last update */
+	unsigned int resolution;	/* current period resolution in ns */
 	unsigned int lost;		/* counter of master tick lost */
 	unsigned int overrun;		/* count of read queue overruns */
 	unsigned int queue;		/* used queue size */
@@ -581,13 +636,18 @@
 enum {
 	SNDRV_TIMER_IOCTL_PVERSION = _IOR('T', 0x00, int),
 	SNDRV_TIMER_IOCTL_NEXT_DEVICE = _IOWR('T', 0x01, struct sndrv_timer_id),
+	SNDRV_TIMER_IOCTL_TREAD = _IOW('T', 0x02, int),
+	SNDRV_TIMER_IOCTL_GINFO = _IOWR('T', 0x03, struct sndrv_timer_ginfo),
+	SNDRV_TIMER_IOCTL_GPARAMS = _IOW('T', 0x04, struct sndrv_timer_gparams),
+	SNDRV_TIMER_IOCTL_GSTATUS = _IOWR('T', 0x05, struct sndrv_timer_gstatus),
 	SNDRV_TIMER_IOCTL_SELECT = _IOW('T', 0x10, struct sndrv_timer_select),
 	SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct sndrv_timer_info),
 	SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct sndrv_timer_params),
-	SNDRV_TIMER_IOCTL_STATUS = _IOW('T', 0x14, struct sndrv_timer_status),
+	SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct sndrv_timer_status),
 	SNDRV_TIMER_IOCTL_START = _IO('T', 0x20),
 	SNDRV_TIMER_IOCTL_STOP = _IO('T', 0x21),
 	SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0x22),
+	SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0x23),
 };
 
 struct sndrv_timer_read {
@@ -595,13 +655,33 @@
 	unsigned int ticks;
 };
 
+enum sndrv_timer_event {
+	SNDRV_TIMER_EVENT_RESOLUTION = 0,	/* val = resolution in ns */
+	SNDRV_TIMER_EVENT_TICK,			/* val = ticks */
+	SNDRV_TIMER_EVENT_START,		/* val = resolution in ns */
+	SNDRV_TIMER_EVENT_STOP,			/* val = 0 */
+	SNDRV_TIMER_EVENT_CONTINUE,		/* val = resolution in ns */
+	SNDRV_TIMER_EVENT_PAUSE,		/* val = 0 */
+	/* master timer events for slave timer instances */
+	SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
+	SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
+	SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
+	SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
+};
+
+struct sndrv_timer_tread {
+	enum sndrv_timer_event event;
+	struct timespec tstamp;
+	unsigned int val;
+};
+
 /****************************************************************************
  *                                                                          *
  *        Section for driver control interface - /dev/snd/control?          *
  *                                                                          *
  ****************************************************************************/
 
-#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 0)
+#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 1)
 
 struct sndrv_ctl_card_info {
 	int card;			/* card number */
@@ -642,6 +722,7 @@
 #define SNDRV_CTL_ELEM_ACCESS_WRITE		(1<<1)
 #define SNDRV_CTL_ELEM_ACCESS_READWRITE		(SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
 #define SNDRV_CTL_ELEM_ACCESS_VOLATILE		(1<<2)	/* control value may be changed without a notification */
+#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP		(1<<2)	/* when was control changed */
 #define SNDRV_CTL_ELEM_ACCESS_INACTIVE		(1<<8)	/* control does actually nothing, but may be updated */
 #define SNDRV_CTL_ELEM_ACCESS_LOCK		(1<<9)	/* write lock */
 #define SNDRV_CTL_ELEM_ACCESS_OWNER		(1<<10)	/* write lock owner */
@@ -722,7 +803,8 @@
 		} bytes;
 		struct sndrv_aes_iec958 iec958;
         } value;                /* RO */
-        unsigned char reserved[128];
+	struct timespec tstamp;
+        unsigned char reserved[128-sizeof(struct timespec)];
 };
 
 enum {
diff -urN linux-2.5.65-bk1/include/sound/core.h linux-2.5.65-bk2/include/sound/core.h
--- linux-2.5.65-bk1/include/sound/core.h	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/include/sound/core.h	Mon Mar 31 12:39:51 2003
@@ -27,7 +27,7 @@
 #include <linux/rwsem.h>		/* struct rw_semaphore */
 
 /* Typedef's */
-typedef struct timeval snd_timestamp_t;
+typedef struct timespec snd_timestamp_t;
 typedef struct sndrv_interval snd_interval_t;
 typedef enum sndrv_card_type snd_card_type;
 typedef struct sndrv_xferi snd_xferi_t;
@@ -275,32 +275,6 @@
 #endif
 void *snd_kcalloc(size_t size, int flags);
 char *snd_kmalloc_strdup(const char *string, int flags);
-void *snd_malloc_pages(unsigned long size, unsigned int dma_flags);
-void *snd_malloc_pages_fallback(unsigned long size, unsigned int dma_flags, unsigned long *res_size);
-void snd_free_pages(void *ptr, unsigned long size);
-#ifdef CONFIG_PCI
-void *snd_malloc_pci_pages(struct pci_dev *pci, unsigned long size, dma_addr_t *dma_addr);
-void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, unsigned long size, dma_addr_t *dma_addr, unsigned long *res_size);
-void snd_free_pci_pages(struct pci_dev *pci, unsigned long size, void *ptr, dma_addr_t dma_addr);
-void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *dma_addr);
-#define snd_free_pci_page(pci,ptr,addr) snd_free_pci_pages(pci,PAGE_SIZE,ptr,addr)
-#endif
-#ifdef CONFIG_SBUS
-void *snd_malloc_sbus_pages(struct sbus_dev *sdev, unsigned long size, dma_addr_t *dma_addr);
-void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, unsigned long size, dma_addr_t *dma_addr, unsigned long *res_size);
-void snd_free_sbus_pages(struct sbus_dev *sdev, unsigned long size, void *ptr, dma_addr_t dma_addr);
-#endif
-#ifdef CONFIG_ISA
-#ifdef CONFIG_PCI
-#define snd_malloc_isa_pages(size, dma_addr) snd_malloc_pci_pages(NULL, size, dma_addr)
-#define snd_malloc_isa_pages_fallback(size, dma_addr, res_size) snd_malloc_pci_pages_fallback(NULL, size, dma_addr, res_size)
-#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pci_pages(NULL, size, ptr, dma_addr)
-#else /* !CONFIG_PCI */
-void *snd_malloc_isa_pages(unsigned long size, dma_addr_t *dma_addr);
-void *snd_malloc_isa_pages_fallback(unsigned long size, dma_addr_t *dma_addr, unsigned long *res_size);
-#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pages(ptr, size)
-#endif /* CONFIG_PCI */
-#endif /* CONFIG_ISA */
 int copy_to_user_fromio(void *dst, unsigned long src, size_t count);
 int copy_from_user_toio(unsigned long dst, const void *src, size_t count);
 
@@ -450,9 +424,27 @@
 #define snd_BUG() snd_assert(0, )
 
 
-#define snd_timestamp_now(tstamp) do_gettimeofday(tstamp)
-#define snd_timestamp_zero(tstamp) do { (tstamp)->tv_sec = 0; (tstamp)->tv_usec = 0; } while (0)
-#define snd_timestamp_null(tstamp) ((tstamp)->tv_sec == 0 && (tstamp)->tv_usec ==0)
+static inline void snd_timestamp_now(struct timespec *tstamp, int timespec)
+{
+	struct timeval val;
+	/* FIXME: use a linear time source */
+	do_gettimeofday(&val);
+	tstamp->tv_sec = val.tv_sec;
+	tstamp->tv_nsec = val.tv_usec;
+	if (timespec)
+		tstamp->tv_nsec *= 1000L;
+}
+
+static inline void snd_timestamp_zero(struct timespec *tstamp)
+{
+	tstamp->tv_sec = 0;
+	tstamp->tv_nsec = 0;
+}
+
+static inline int snd_timestamp_null(struct timespec *tstamp)
+{
+	return tstamp->tv_sec == 0 && tstamp->tv_nsec == 0;
+}
 
 #define SNDRV_OSS_VERSION         ((3<<16)|(8<<8)|(1<<4)|(0))	/* 3.8.1a */
 
diff -urN linux-2.5.65-bk1/include/sound/driver.h linux-2.5.65-bk2/include/sound/driver.h
--- linux-2.5.65-bk1/include/sound/driver.h	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/include/sound/driver.h	Mon Mar 31 12:39:51 2003
@@ -49,20 +49,6 @@
  *  ==========================================================================
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
-#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
-/*
- * Here a dirty hack for 2.4 kernels.. See sound/core/memory.c.
- */
-#define HACK_PCI_ALLOC_CONSISTENT
-#include <linux/pci.h>
-void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
-				    dma_addr_t *dma_handle);
-#undef pci_alloc_consistent
-#define pci_alloc_consistent snd_pci_hack_alloc_consistent
-#endif /* i386 or ppc */
-#endif /* 2.4.0 */
-
 #ifdef CONFIG_SND_DEBUG_MEMORY
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
diff -urN linux-2.5.65-bk1/include/sound/emu10k1.h linux-2.5.65-bk2/include/sound/emu10k1.h
--- linux-2.5.65-bk1/include/sound/emu10k1.h	Mon Mar 17 13:43:49 2003
+++ linux-2.5.65-bk2/include/sound/emu10k1.h	Mon Mar 31 12:39:51 2003
@@ -49,6 +49,8 @@
 #define NUM_G           64              /* use all channels */
 #define NUM_FXSENDS     4
 
+#define EMU10K1_DMA_MASK	0x1fffffffUL
+#define AUDIGY_DMA_MASK		0xffffffffUL
 
 #define TMEMSIZE        256*1024
 #define TMEMSIZEREG     4
@@ -232,6 +234,8 @@
 #define A_GPINPUT_MASK		0xff00
 #define A_GPOUTPUT_MASK		0x00ff
 #define A_IOCFG_GPOUT0		0x0044		/* analog/digital? */
+#define A_IOCFG_GPOUT1		0x0002		/* IR */
+#define A_IOCFG_GPOUT2		0x0001		/* IR */
 
 #define TIMER			0x1a		/* Timer terminal count register		*/
 						/* NOTE: After the rate is changed, a maximum	*/
@@ -936,6 +940,7 @@
 	unsigned short model;			/* subsystem id */
 	unsigned int card_type;			/* EMU10K1_CARD_* */
 	unsigned int ecard_ctrl;		/* ecard control bits */
+	unsigned long dma_mask;			/* PCI DMA mask */
 	int max_cache_pages;			/* max memory size / PAGE_SIZE */
 	void *silent_page;			/* silent page */
 	dma_addr_t silent_page_dmaaddr;
diff -urN linux-2.5.65-bk1/include/sound/hwdep.h linux-2.5.65-bk2/include/sound/hwdep.h
--- linux-2.5.65-bk1/include/sound/hwdep.h	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/include/sound/hwdep.h	Mon Mar 31 12:39:51 2003
@@ -27,6 +27,8 @@
 
 typedef enum sndrv_hwdep_iface snd_hwdep_iface_t;
 typedef struct sndrv_hwdep_info snd_hwdep_info_t;
+typedef struct sndrv_hwdep_dsp_status snd_hwdep_dsp_status_t;
+typedef struct sndrv_hwdep_dsp_image snd_hwdep_dsp_image_t;
 
 typedef struct _snd_hwdep_ops {
 	long long (*llseek) (snd_hwdep_t *hw, struct file * file, long long offset, int orig);
@@ -37,6 +39,8 @@
 	unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait);
 	int (*ioctl) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
 	int (*mmap) (snd_hwdep_t * hw, struct file * file, struct vm_area_struct * vma);
+	int (*dsp_status) (snd_hwdep_t * hw, snd_hwdep_dsp_status_t * status);
+	int (*dsp_load) (snd_hwdep_t * hw, snd_hwdep_dsp_image_t * image);
 } snd_hwdep_ops_t;
 
 struct _snd_hwdep {
@@ -56,6 +60,11 @@
 	wait_queue_head_t open_wait;
 	void *private_data;
 	void (*private_free) (snd_hwdep_t *hwdep);
+
+	struct semaphore open_mutex;
+	int used;
+	unsigned int dsp_loaded;
+	unsigned int exclusive: 1;
 };
 
 extern int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep);
diff -urN linux-2.5.65-bk1/include/sound/initval.h linux-2.5.65-bk2/include/sound/initval.h
--- linux-2.5.65-bk1/include/sound/initval.h	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/include/sound/initval.h	Mon Mar 31 12:39:51 2003
@@ -67,7 +67,7 @@
 #define SNDRV_BOOLEAN_TRUE_DESC	"allows:{{0,Disabled},{1,Enabled}},default:1,dialog:check"
 #define SNDRV_BOOLEAN_FALSE_DESC "allows:{{0,Disabled},{1,Enabled}},default:0,dialog:check"
 
-#define SNDRV_ENABLED		"enable:(snd_enable)"
+#define SNDRV_ENABLED		"enable:(enable)"
 
 #define SNDRV_INDEX_DESC	SNDRV_ENABLED ",allows:{{0,7}},unique,skill:required,dialog:list"
 #define SNDRV_ID_DESC		SNDRV_ENABLED ",unique"
diff -urN linux-2.5.65-bk1/include/sound/memalloc.h linux-2.5.65-bk2/include/sound/memalloc.h
--- linux-2.5.65-bk1/include/sound/memalloc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/include/sound/memalloc.h	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,193 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *                   Takashi Iwai <tiwai@suse.de>
+ * 
+ *  Generic memory allocators
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef __SOUND_MEMALLOC_H
+#define __SOUND_MEMALLOC_H
+
+#include <linux/pci.h>
+#ifdef CONFIG_SBUS
+#include <asm/sbus.h>
+#endif
+
+/*
+ * buffer device info
+ */
+struct snd_dma_device {
+	int type;			/* SNDRV_MEM_TYPE_XXX */
+	union {
+		struct pci_dev *pci;	/* for PCI and PCI-SG types */
+		unsigned int flags;	/* GFP_XXX for continous and ISA types */
+#ifdef CONFIG_SBUS
+		struct sbus_dev *sbus;	/* for SBUS type */
+#endif
+	} dev;
+	unsigned int id;		/* a unique ID */
+};
+
+/*
+ * buffer types
+ */
+#define SNDRV_DMA_TYPE_UNKNOWN		0	/* not defined */
+#define SNDRV_DMA_TYPE_CONTINUOUS	1	/* continuous no-DMA memory */
+#define SNDRV_DMA_TYPE_ISA		2	/* ISA continuous */
+#define SNDRV_DMA_TYPE_PCI		3	/* PCI continuous */
+#define SNDRV_DMA_TYPE_SBUS		4	/* SBUS continuous */
+#define SNDRV_DMA_TYPE_PCI_SG		5	/* PCI SG-buffer */
+
+#ifdef CONFIG_PCI
+/*
+ * compose a snd_dma_device struct for the PCI device
+ */
+static inline void snd_dma_device_pci(struct snd_dma_device *dev, struct pci_dev *pci, unsigned int id)
+{
+	memset(dev, 0, sizeof(*dev));
+	dev->type = SNDRV_DMA_TYPE_PCI;
+	dev->dev.pci = pci;
+	dev->id = id;
+}
+#endif
+
+
+/*
+ * info for buffer allocation
+ */
+struct snd_dma_buffer {
+	unsigned char *area;	/* virtual pointer */
+	dma_addr_t addr;	/* physical address */
+	size_t bytes;		/* buffer size in bytes */
+	void *private_data;	/* private for allocator; don't touch */
+};
+
+/* allocate/release a buffer */
+int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size, struct snd_dma_buffer *dmab);
+void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
+
+/* buffer-preservation managements */
+size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
+int snd_dma_free_reserved(const struct snd_dma_device *dev);
+int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
+
+
+/*
+ * Generic memory allocators
+ */
+
+/*
+ * continuous pages
+ */
+void *snd_malloc_pages(size_t size, unsigned int gfp_flags);
+void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size);
+void snd_free_pages(void *ptr, size_t size);
+
+#ifdef CONFIG_PCI
+/*
+ * PCI continuous pages
+ */
+void *snd_malloc_pci_pages(struct pci_dev *pci, size_t size, dma_addr_t *dma_addr);
+void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, size_t size, dma_addr_t *dma_addr, size_t *res_size);
+void snd_free_pci_pages(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t dma_addr);
+/* one page allocation */
+void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *dma_addr);
+#define snd_free_pci_page(pci,ptr,addr) snd_free_pci_pages(pci,PAGE_SIZE,ptr,addr)
+#endif
+
+#ifdef CONFIG_SBUS
+/*
+ * SBUS continuous pages
+ */
+void *snd_malloc_sbus_pages(struct sbus_dev *sdev, size_t size, dma_addr_t *dma_addr);
+void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, size_t size, dma_addr_t *dma_addr, size_t *res_size);
+void snd_free_sbus_pages(struct sbus_dev *sdev, size_t size, void *ptr, dma_addr_t dma_addr);
+#endif
+
+#ifdef CONFIG_ISA
+/*
+ * ISA continuous pages
+ */
+void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr);
+void *snd_malloc_isa_pages_fallback(size_t size, dma_addr_t *dma_addr, size_t *res_size);
+void snd_free_isa_pages(size_t size, void *ptr, dma_addr_t addr);
+#ifdef CONFIG_PCI
+#define snd_malloc_isa_pages(size, dma_addr) snd_malloc_pci_pages(NULL, size, dma_addr)
+#define snd_malloc_isa_pages_fallback(size, dma_addr, res_size) snd_malloc_pci_pages_fallback(NULL, size, dma_addr, res_size)
+#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pci_pages(NULL, size, ptr, dma_addr)
+#else /* !CONFIG_PCI */
+#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pages(ptr, size)
+#endif /* CONFIG_PCI */
+#endif /* CONFIG_ISA */
+
+#ifdef CONFIG_PCI
+/*
+ * Scatter-Gather PCI pages
+ */
+struct snd_sg_page {
+	void *buf;
+	dma_addr_t addr;
+};
+
+struct snd_sg_buf {
+	int size;	/* allocated byte size */
+	int pages;	/* allocated pages */
+	int tblsize;	/* allocated table size */
+	struct snd_sg_page *table;	/* address table */
+	struct page **page_table;	/* page table (for vmap/vunmap) */
+	struct pci_dev *pci;
+};
+
+void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer *dmab);
+int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
+
+/*
+ * return the pages matching with the given byte size
+ */
+static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
+{
+	return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
+/*
+ * return the physical address at the corresponding offset
+ */
+static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
+{
+	return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
+}
+#endif /* CONFIG_PCI */
+
+
+/*
+ * wrappers
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
+#ifdef CONFIG_PCI
+#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
+#define HACK_PCI_ALLOC_CONSISTENT
+/* a hack for 2.4/5 kernels for better allocation of large buffers */
+void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
+				    dma_addr_t *dma_handle);
+#endif /* arch */
+#endif /* CONFIG_PCI */
+#endif /* LINUX >= 2.4.0 */
+
+
+#endif /* __SOUND_MEMALLOC_H */
diff -urN linux-2.5.65-bk1/include/sound/mpu401.h linux-2.5.65-bk2/include/sound/mpu401.h
--- linux-2.5.65-bk1/include/sound/mpu401.h	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/include/sound/mpu401.h	Mon Mar 31 12:39:51 2003
@@ -42,6 +42,7 @@
 #define MPU401_HW_ALS4000		16	/* Avance Logic ALS4000 */
 #define MPU401_HW_INTEL8X0		17	/* Intel8x0 driver */
 #define MPU401_HW_PC98II		18	/* Roland PC98II */
+#define MPU401_HW_AUREAL		19	/* Aureal Vortex */
 
 #define MPU401_MODE_BIT_INPUT		0
 #define MPU401_MODE_BIT_OUTPUT		1
@@ -87,6 +88,9 @@
 	spinlock_t timer_lock;
 
 	struct timer_list timer;
+
+	void (*write) (mpu401_t * mpu, unsigned char data, unsigned long addr);
+	unsigned char (*read) (mpu401_t * mpu, unsigned long addr);
 };
 
 /* I/O ports */
diff -urN linux-2.5.65-bk1/include/sound/pcm.h linux-2.5.65-bk2/include/sound/pcm.h
--- linux-2.5.65-bk1/include/sound/pcm.h	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/include/sound/pcm.h	Mon Mar 31 12:39:51 2003
@@ -24,6 +24,7 @@
  */
 
 #include <sound/asound.h>
+#include <sound/memalloc.h>
 #include <linux/poll.h>
 #include <linux/bitops.h>
 
@@ -49,6 +50,7 @@
 typedef struct sndrv_pcm_mmap_status snd_pcm_mmap_status_t;
 typedef struct sndrv_pcm_mmap_control snd_pcm_mmap_control_t;
 typedef struct sndrv_mask snd_mask_t;
+typedef struct snd_sg_buf snd_pcm_sgbuf_t;
 
 #define _snd_pcm_substream_chip(substream) ((substream)->private_data)
 #define snd_pcm_substream_chip(substream) snd_magic_cast1(chip_t, _snd_pcm_substream_chip(substream), return -ENXIO)
@@ -97,6 +99,7 @@
 	int (*silence)(snd_pcm_substream_t *substream, int channel, 
 		       snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
 	struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
+	int (*ack)(snd_pcm_substream_t *substream);
 } snd_pcm_ops_t;
 
 /*
@@ -120,13 +123,6 @@
 #define SNDRV_PCM_TRIGGER_SUSPEND	5
 #define SNDRV_PCM_TRIGGER_RESUME	6
 
-#define SNDRV_PCM_DMA_TYPE_UNKNOWN	0	/* not defined */
-#define SNDRV_PCM_DMA_TYPE_CONTINUOUS	1	/* continuous no-DMA memory */
-#define SNDRV_PCM_DMA_TYPE_ISA		2	/* ISA continuous */
-#define SNDRV_PCM_DMA_TYPE_PCI		3	/* PCI continuous */
-#define SNDRV_PCM_DMA_TYPE_SBUS		4	/* SBUS continuous */
-#define SNDRV_PCM_DMA_TYPE_PCI_SG	5	/* PCI SG-buffer */
-
 /* If you change this don't forget to change rates[] table in pcm_native.c */
 #define SNDRV_PCM_RATE_5512		(1<<0)		/* 5512Hz */
 #define SNDRV_PCM_RATE_8000		(1<<1)		/* 8000Hz */
@@ -281,13 +277,6 @@
 	unsigned int mask;
 } snd_pcm_hw_constraint_list_t;
 
-struct snd_pcm_dma_buffer {
-	unsigned char *area;
-	dma_addr_t addr;
-	unsigned long bytes;
-	void *private_data; /* for allocator */
-};
-
 struct _snd_pcm_runtime {
 	/* -- Status -- */
 	snd_pcm_substream_t *trigger_master;
@@ -316,6 +305,7 @@
 	unsigned int rate_den;
 
 	/* -- SW params -- */
+	int tstamp_timespec;		/* use timeval (0) or timespec (1) */
 	snd_pcm_tstamp_t tstamp_mode;	/* mmap timestamp is updated */
   	unsigned int period_step;
 	unsigned int sleep_min;		/* min ticks to sleep */
@@ -361,7 +351,7 @@
 	/* -- DMA -- */           
 	unsigned char *dma_area;	/* DMA area */
 	dma_addr_t dma_addr;		/* physical bus address (not accessible from main CPU) */
-	unsigned long dma_bytes;	/* size of DMA area */
+	size_t dma_bytes;		/* size of DMA area */
 	void *dma_private;		/* private DMA data for the memory allocator */
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
@@ -378,17 +368,17 @@
 	char name[32];			/* substream name */
 	int stream;			/* stream (direction) */
 	size_t buffer_bytes_max;	/* limit ring buffer size */
-	int dma_type;			
-	struct snd_pcm_dma_buffer dma_buffer;
+	struct snd_dma_device dma_device;
+	struct snd_dma_buffer dma_buffer;
 	size_t dma_max;
-	void *dma_private;
 	/* -- hardware operations -- */
+	unsigned int open_flag: 1;	/* lowlevel device has been opened */
 	snd_pcm_ops_t *ops;
 	/* -- runtime information -- */
 	snd_pcm_runtime_t *runtime;
         /* -- timer section -- */
 	snd_timer_t *timer;		/* timer */
-	int timer_running;		/* time is running */
+	int timer_running: 1;		/* time is running */
 	spinlock_t timer_lock;
 	/* -- next substream -- */
 	snd_pcm_substream_t *next;
@@ -879,7 +869,18 @@
 					      snd_pcm_t *pcm,
 					      size_t size,
 					      size_t max);
+int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci,
+				     snd_pcm_substream_t *substream,
+				     size_t size, size_t max);
+int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci,
+					     snd_pcm_t *pcm,
+					     size_t size, size_t max);
+#define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_private)
+#define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size)
+#define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs)
+struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
 #endif
+
 #ifdef CONFIG_SBUS
 int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev,
 				       snd_pcm_substream_t *substream,
diff -urN linux-2.5.65-bk1/include/sound/pcm_sgbuf.h linux-2.5.65-bk2/include/sound/pcm_sgbuf.h
--- linux-2.5.65-bk1/include/sound/pcm_sgbuf.h	Mon Mar 17 13:44:38 2003
+++ linux-2.5.65-bk2/include/sound/pcm_sgbuf.h	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-#ifndef __SOUND_PCM_SGBUF_H
-#define __SOUND_PCM_SGBUF_H
-
-/*
- * Scatter-Gather PCM access
- *
- *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-struct snd_sg_page {
-	void *buf;
-	dma_addr_t addr;
-};
-
-struct snd_sg_buf {
-	int size;	/* allocated byte size (= runtime->dma_bytes) */
-	int pages;	/* allocated pages */
-	int tblsize;	/* allocated table size */
-	struct snd_sg_page *table;
-	struct page **page_table;
-	struct pci_dev *pci;
-};
-
-typedef struct snd_sg_buf snd_pcm_sgbuf_t; /* for magic cast */
-
-/*
- * return the pages matching with the given byte size
- */
-static inline unsigned int snd_pcm_sgbuf_pages(size_t size)
-{
-	return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-}
-
-/*
- * return the physical address at the corresponding offset
- */
-static inline dma_addr_t snd_pcm_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
-{
-	return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
-}
-
-void *snd_pcm_sgbuf_alloc_pages(struct pci_dev *pci, size_t size, struct snd_pcm_dma_buffer *dmab);
-int snd_pcm_sgbuf_free_pages(struct snd_pcm_dma_buffer *dmab);
-
-int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci, snd_pcm_substream_t *substream, size_t size, size_t max);
-int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci, snd_pcm_t *pcm, size_t size, size_t max);
-
-#define _snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_private)
-#define snd_pcm_substream_sgbuf(substream) snd_magic_cast(snd_pcm_sgbuf_t, _snd_pcm_substream_sgbuf(substream), return -ENXIO)
-
-struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
-
-#endif /* __SOUND_PCM_SGBUF_H */
diff -urN linux-2.5.65-bk1/include/sound/seq_kernel.h linux-2.5.65-bk2/include/sound/seq_kernel.h
--- linux-2.5.65-bk1/include/sound/seq_kernel.h	Mon Mar 17 13:44:46 2003
+++ linux-2.5.65-bk2/include/sound/seq_kernel.h	Mon Mar 31 12:39:51 2003
@@ -174,7 +174,7 @@
 
 /* port attach/detach */
 int snd_seq_event_port_attach(int client, snd_seq_port_callback_t *pcbp,
-			      int cap, int type, int midi_channels, char *portname);
+			      int cap, int type, int midi_channels, int midi_voices, char *portname);
 int snd_seq_event_port_detach(int client, int port);
 
 #endif /* __SOUND_SEQ_KERNEL_H */
diff -urN linux-2.5.65-bk1/include/sound/sndmagic.h linux-2.5.65-bk2/include/sound/sndmagic.h
--- linux-2.5.65-bk1/include/sound/sndmagic.h	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/include/sound/sndmagic.h	Mon Mar 31 12:39:51 2003
@@ -108,7 +108,7 @@
 #define snd_pcm_proc_private_t_magic		0xa15a0104
 #define snd_pcm_oss_file_t_magic		0xa15a0105
 #define snd_mixer_oss_t_magic			0xa15a0106
-#define snd_pcm_sgbuf_t_magic			0xa15a0107
+// #define snd_pcm_sgbuf_t_magic			0xa15a0107
 
 #define snd_info_private_data_t_magic		0xa15a0201
 #define snd_info_entry_t_magic			0xa15a0202
@@ -174,6 +174,7 @@
 #define m3_dma_t_magic				0xa15a3202
 #define nm256_t_magic				0xa15a3301
 #define nm256_dma_t_magic			0xa15a3302
+#define sam9407_t_magic				0xa15a3401
 #define pmac_t_magic				0xa15a3501
 #define ali_t_magic				0xa15a3601
 #define mtpav_t_magic				0xa15a3701
@@ -190,6 +191,8 @@
 #define snd_usb_midi_t_magic			0xa15a3f01
 #define snd_usb_midi_out_endpoint_t_magic	0xa15a3f02
 #define snd_usb_midi_in_endpoint_t_magic	0xa15a3f03
+#define ak4117_t_magic				0xa15a4000
+#define psic_t_magic				0xa15a4100
 
 
 #else
diff -urN linux-2.5.65-bk1/include/sound/timer.h linux-2.5.65-bk2/include/sound/timer.h
--- linux-2.5.65-bk1/include/sound/timer.h	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/include/sound/timer.h	Mon Mar 31 12:39:51 2003
@@ -3,7 +3,8 @@
 
 /*
  *  Timer abstract layer
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
+ *		     Abramo Bagnara <abramo@alsa-project.org>
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -29,11 +30,15 @@
 typedef enum sndrv_timer_slave_class snd_timer_slave_class_t;
 typedef enum sndrv_timer_global snd_timer_global_t;
 typedef struct sndrv_timer_id snd_timer_id_t;
+typedef struct sndrv_timer_ginfo snd_timer_ginfo_t;
+typedef struct sndrv_timer_gparams snd_timer_gparams_t;
+typedef struct sndrv_timer_gstatus snd_timer_gstatus_t;
 typedef struct sndrv_timer_select snd_timer_select_t;
 typedef struct sndrv_timer_info snd_timer_info_t;
 typedef struct sndrv_timer_params snd_timer_params_t;
 typedef struct sndrv_timer_status snd_timer_status_t;
 typedef struct sndrv_timer_read snd_timer_read_t;
+typedef struct sndrv_timer_tread snd_timer_tread_t;
 
 #define _snd_timer_chip(timer) ((timer)->private_data)
 #define snd_timer_chip(timer) snd_magic_cast1(chip_t, _snd_timer_chip(timer), return -ENXIO)
@@ -54,16 +59,21 @@
 #define SNDRV_TIMER_IFLG_AUTO	  0x00000008	/* auto restart */
 #define SNDRV_TIMER_IFLG_FAST	  0x00000010	/* fast callback (do not use tasklet) */
 #define SNDRV_TIMER_IFLG_CALLBACK 0x00000020	/* timer callback is active */
+#define SNDRV_TIMER_IFLG_EXCLUSIVE 0x00000040	/* exclusive owner - no more instances */
 
 #define SNDRV_TIMER_FLG_CHANGE	0x00000001
 #define SNDRV_TIMER_FLG_RESCHED	0x00000002	/* need reschedule */
 
 typedef void (*snd_timer_callback_t) (snd_timer_instance_t * timeri, unsigned long ticks, unsigned long resolution);
+typedef void (*snd_timer_ccallback_t) (snd_timer_instance_t * timeri, enum sndrv_timer_event event,
+				       struct timespec * tstamp, unsigned long resolution);
 
 struct _snd_timer_hardware {
 	/* -- must be filled with low-level driver */
 	unsigned int flags;		/* various flags */
 	unsigned long resolution;	/* average timer resolution for one tick in nsec */
+	unsigned long resolution_min;	/* minimal resolution */
+	unsigned long resolution_max;	/* maximal resolution */
 	unsigned long ticks;		/* max timer ticks per interrupt */
 	/* -- low-level functions -- */
 	int (*open) (snd_timer_t * timer);
@@ -71,6 +81,8 @@
 	unsigned long (*c_resolution) (snd_timer_t * timer);
 	int (*start) (snd_timer_t * timer);
 	int (*stop) (snd_timer_t * timer);
+	int (*set_period) (snd_timer_t * timer, unsigned long period_num, unsigned long period_den);
+	int (*precise_resolution) (snd_timer_t * timer, unsigned long *num, unsigned long *den);
 };
 
 struct _snd_timer {
@@ -102,6 +114,7 @@
 	void *private_data;
 	void (*private_free) (snd_timer_instance_t *ti);
 	snd_timer_callback_t callback;
+	snd_timer_ccallback_t ccallback;
 	void *callback_data;
 	unsigned long ticks;		/* auto-load ticks when expired */
 	unsigned long cticks;		/* current ticks */
@@ -123,20 +136,19 @@
  */
 
 extern int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t ** rtimer);
+extern void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct timespec *tstamp);
 extern int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer);
 extern int snd_timer_global_free(snd_timer_t *timer);
 extern int snd_timer_global_register(snd_timer_t *timer);
 extern int snd_timer_global_unregister(snd_timer_t *timer);
 
-extern snd_timer_instance_t *snd_timer_open(char *owner, snd_timer_id_t *tid, unsigned int slave_id);
+extern int snd_timer_open(snd_timer_instance_t ** ti, char *owner, snd_timer_id_t *tid, unsigned int slave_id);
 extern int snd_timer_close(snd_timer_instance_t * timeri);
-extern int snd_timer_set_owner(snd_timer_instance_t * timeri, pid_t pid, gid_t gid);
-extern int snd_timer_reset_owner(snd_timer_instance_t * timeri);
-extern int snd_timer_set_resolution(snd_timer_instance_t * timeri, unsigned long resolution);
 extern unsigned long snd_timer_resolution(snd_timer_instance_t * timeri);
 extern int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks);
 extern int snd_timer_stop(snd_timer_instance_t * timeri);
 extern int snd_timer_continue(snd_timer_instance_t * timeri);
+extern int snd_timer_pause(snd_timer_instance_t * timeri);
 
 extern void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left);
 
diff -urN linux-2.5.65-bk1/include/sound/trident.h linux-2.5.65-bk2/include/sound/trident.h
--- linux-2.5.65-bk1/include/sound/trident.h	Mon Mar 17 13:44:08 2003
+++ linux-2.5.65-bk2/include/sound/trident.h	Mon Mar 31 12:39:51 2003
@@ -365,10 +365,16 @@
 	int running: 1,
             capture: 1,
             spdif: 1,
-            foldback: 1;
+            foldback: 1,
+            isync: 1,
+            isync2: 1,
+            isync3: 1;
 	int foldback_chan;		/* foldback subdevice number */
 	unsigned int stimer;		/* global sample timer (to detect spurious interrupts) */
 	unsigned int spurious_threshold; /* spurious threshold */
+	unsigned int isync_mark;
+	unsigned int isync_max;
+	unsigned int isync_ESO;
 
 	/* --- */
 
@@ -448,6 +454,7 @@
 	snd_seq_device_t *seq_dev;
 
 	ac97_t *ac97;
+	ac97_t *ac97_sec;
 
 	unsigned int musicvol_wavevol;
 	snd_trident_pcm_mixer_t pcm_mixer[32];
diff -urN linux-2.5.65-bk1/include/sound/uda1341.h linux-2.5.65-bk2/include/sound/uda1341.h
--- linux-2.5.65-bk1/include/sound/uda1341.h	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/include/sound/uda1341.h	Mon Mar 31 12:39:51 2003
@@ -15,11 +15,16 @@
  *                           features support
  */
 
-/* $Id: uda1341.h,v 1.2 2002/04/17 07:53:22 perex Exp $ */
+/* $Id: uda1341.h,v 1.4 2003/02/25 12:48:16 perex Exp $ */
 
 #define UDA1341_ALSA_NAME "snd-uda1341"
 
 /*
+ * Default rate set after inicialization
+ */
+#define AUDIO_RATE_DEFAULT	44100
+
+/*
  * UDA1341 L3 address and command types
  */
 #define UDA1341_L3ADDR		5
diff -urN linux-2.5.65-bk1/include/sound/version.h linux-2.5.65-bk2/include/sound/version.h
--- linux-2.5.65-bk1/include/sound/version.h	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/include/sound/version.h	Mon Mar 31 12:39:51 2003
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "0.9.0rc7"
-#define CONFIG_SND_DATE " (Sat Feb 15 15:01:21 2003 UTC)"
+#define CONFIG_SND_VERSION "0.9.2"
+#define CONFIG_SND_DATE " (Thu Mar 20 13:31:57 2003 UTC)"
diff -urN linux-2.5.65-bk1/kernel/cpufreq.c linux-2.5.65-bk2/kernel/cpufreq.c
--- linux-2.5.65-bk1/kernel/cpufreq.c	Mon Mar 17 13:43:46 2003
+++ linux-2.5.65-bk2/kernel/cpufreq.c	Mon Mar 31 12:39:51 2003
@@ -46,7 +46,7 @@
 static DECLARE_RWSEM		(cpufreq_notifier_rwsem);
 
 
-LIST_HEAD(cpufreq_governor_list);
+static LIST_HEAD(cpufreq_governor_list);
 static DECLARE_MUTEX		(cpufreq_governor_sem);
 
 static struct device_interface cpufreq_interface;
diff -urN linux-2.5.65-bk1/kernel/posix-timers.c linux-2.5.65-bk2/kernel/posix-timers.c
--- linux-2.5.65-bk1/kernel/posix-timers.c	Mon Mar 31 12:39:48 2003
+++ linux-2.5.65-bk2/kernel/posix-timers.c	Mon Mar 31 12:39:51 2003
@@ -182,8 +182,7 @@
 
 __initcall(init_posix_timers);
 
-static inline int
-tstojiffie(struct timespec *tp, int res, u64 *jiff)
+static void tstojiffie(struct timespec *tp, int res, u64 *jiff)
 {
 	unsigned long sec = tp->tv_sec;
 	long nsec = tp->tv_nsec + res - 1;
@@ -212,17 +211,14 @@
 	 * Split to jiffie and sub jiffie
 	 */
 	*jiff += nsec / (NSEC_PER_SEC / HZ);
-	/*
-	 * We trust that the optimizer will use the remainder from the 
-	 * above div in the following operation as long as they are close. 
-	 */
-	return 0;
 }
+
 static void
 tstotimer(struct itimerspec *time, struct k_itimer *timer)
 {
 	u64 result;
 	int res = posix_clocks[timer->it_clock].res;
+
 	tstojiffie(&time->it_value, res, &result);
 	timer->it_timer.expires = (unsigned long)result;
 	tstojiffie(&time->it_interval, res, &result);
@@ -1195,6 +1191,7 @@
 	return ret;
 
 }
+
 long
 do_clock_nanosleep(clockid_t which_clock, int flags, struct timespec *tsave)
 {
@@ -1225,41 +1222,40 @@
 		rq_time = (rq_time << 32) + restart_block->arg2;
 		if (!rq_time)
 			return -EINTR;
-		if (rq_time <= get_jiffies_64())
-			return 0;
+		left = rq_time - get_jiffies_64();
+		if (left <= 0LL)
+			return 0;	/* Already passed */
 	}
 
 	if (abs && (posix_clocks[which_clock].clock_get !=
 		    posix_clocks[CLOCK_MONOTONIC].clock_get)) {
 		add_wait_queue(&nanosleep_abs_wqueue, &abs_wqueue);
 	}
+
 	do {
 		t = *tsave;
-		if (abs || !rq_time){
+		if (abs || !rq_time) {
 			adjust_abs_time(&posix_clocks[which_clock], &t, abs);
-
 			tstojiffie(&t, posix_clocks[which_clock].res, &rq_time);
 		}
-#if (BITS_PER_LONG < 64)
-		if ((rq_time - get_jiffies_64()) > MAX_JIFFY_OFFSET){
-			new_timer.expires = MAX_JIFFY_OFFSET;
-		}else
-#endif
-		{
-			new_timer.expires = (long)rq_time;
-		}
-		current->state = TASK_INTERRUPTIBLE;
+
+		left = rq_time - get_jiffies_64();
+		if (left >= MAX_JIFFY_OFFSET)
+			left = MAX_JIFFY_OFFSET;
+		if (left < 0)
+			break;
+
+		new_timer.expires = jiffies + left;
+		__set_current_state(TASK_INTERRUPTIBLE);
 		add_timer(&new_timer);
 
 		schedule();
 
 		del_timer_sync(&new_timer);
 		left = rq_time - get_jiffies_64();
-	}
-	while ( (left > 0)  &&
-		!test_thread_flag(TIF_SIGPENDING));
+	} while (left > 0 && !test_thread_flag(TIF_SIGPENDING));
 
-	if( abs_wqueue.task_list.next)
+	if (abs_wqueue.task_list.next)
 		finish_wait(&nanosleep_abs_wqueue, &abs_wqueue);
 
 	if (left > 0) {
diff -urN linux-2.5.65-bk1/kernel/sys.c linux-2.5.65-bk2/kernel/sys.c
--- linux-2.5.65-bk1/kernel/sys.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/kernel/sys.c	Mon Mar 31 12:39:51 2003
@@ -209,6 +209,23 @@
 cond_syscall(sys_swapoff)
 cond_syscall(sys_init_module)
 cond_syscall(sys_delete_module)
+cond_syscall(sys_socketpair)
+cond_syscall(sys_bind)
+cond_syscall(sys_listen)
+cond_syscall(sys_accept)
+cond_syscall(sys_connect)
+cond_syscall(sys_getsockname)
+cond_syscall(sys_getpeername)
+cond_syscall(sys_sendto)
+cond_syscall(sys_send)
+cond_syscall(sys_recvfrom)
+cond_syscall(sys_recv)
+cond_syscall(sys_setsockopt)
+cond_syscall(sys_getsockopt)
+cond_syscall(sys_shutdown)
+cond_syscall(sys_sendmsg)
+cond_syscall(sys_recvmsg)
+cond_syscall(sys_socketcall)
 
 static int set_one_prio(struct task_struct *p, int niceval, int error)
 {
diff -urN linux-2.5.65-bk1/kernel/timer.c linux-2.5.65-bk2/kernel/timer.c
--- linux-2.5.65-bk1/kernel/timer.c	Mon Mar 31 12:39:48 2003
+++ linux-2.5.65-bk2/kernel/timer.c	Mon Mar 31 12:39:51 2003
@@ -1199,11 +1199,23 @@
 		INIT_LIST_HEAD(base->tv1.vec + j);
 
 	base->timer_jiffies = INITIAL_JIFFIES;
-	base->tv1.index = INITIAL_JIFFIES & TVR_MASK;
-	base->tv2.index = (INITIAL_JIFFIES >> TVR_BITS) & TVN_MASK;
-	base->tv3.index = (INITIAL_JIFFIES >> (TVR_BITS+TVN_BITS)) & TVN_MASK;
-	base->tv4.index = (INITIAL_JIFFIES >> (TVR_BITS+2*TVN_BITS)) & TVN_MASK;
-	base->tv5.index = (INITIAL_JIFFIES >> (TVR_BITS+3*TVN_BITS)) & TVN_MASK;
+	/*
+	 * The tv indices are always larger by one compared to the
+	 * respective parts of timer_jiffies. If all lower indices are
+	 * zero at initialisation, this is achieved by an (otherwise
+	 * unneccessary) invocation of the timer cascade on the first
+	 * timer interrupt. If not, we need to take it into account
+	 * here:
+	 */
+	j  = (base->tv1.index = INITIAL_JIFFIES & TVR_MASK) !=0;
+	j |= (base->tv2.index = ((INITIAL_JIFFIES >> TVR_BITS) + j)
+	                        & TVN_MASK) !=0;
+	j |= (base->tv3.index = ((INITIAL_JIFFIES >> (TVR_BITS+TVN_BITS)) + j)
+	                        & TVN_MASK) !=0;
+	j |= (base->tv4.index = ((INITIAL_JIFFIES >> (TVR_BITS+2*TVN_BITS)) + j)
+	                        & TVN_MASK) !=0;
+	      base->tv5.index = ((INITIAL_JIFFIES >> (TVR_BITS+3*TVN_BITS)) + j)
+	                        & TVN_MASK;
 }
 	
 static int __devinit timer_cpu_notify(struct notifier_block *self, 
diff -urN linux-2.5.65-bk1/mm/slab.c linux-2.5.65-bk2/mm/slab.c
--- linux-2.5.65-bk1/mm/slab.c	Mon Mar 31 12:39:48 2003
+++ linux-2.5.65-bk2/mm/slab.c	Mon Mar 31 12:39:51 2003
@@ -2175,7 +2175,9 @@
 	 * The numbers are guessed, we should auto-tune as described by
 	 * Bonwick.
 	 */
-	if (cachep->objsize > PAGE_SIZE)
+	if (cachep->objsize > 131072)
+		limit = 1;
+	else if (cachep->objsize > PAGE_SIZE)
 		limit = 8;
 	else if (cachep->objsize > 1024)
 		limit = 54;
@@ -2192,7 +2194,7 @@
 	if (limit > 32)
 		limit = 32;
 #endif
-	err = do_tune_cpucache(cachep, limit, limit/2);
+	err = do_tune_cpucache(cachep, limit, (limit+1)/2);
 	if (err)
 		printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n",
 					cachep->name, -err);
diff -urN linux-2.5.65-bk1/net/8021q/vlan.c linux-2.5.65-bk2/net/8021q/vlan.c
--- linux-2.5.65-bk1/net/8021q/vlan.c	Mon Mar 17 13:44:39 2003
+++ linux-2.5.65-bk2/net/8021q/vlan.c	Mon Mar 31 12:39:51 2003
@@ -433,7 +433,6 @@
 	/* set up method calls */
 	new_dev->init = vlan_dev_init;
 	new_dev->destructor = vlan_dev_destruct;
-	new_dev->features |= NETIF_F_DYNALLOC ; 
 	    
 	/* new_dev->ifindex = 0;  it will be set when added to
 	 * the global list.
diff -urN linux-2.5.65-bk1/net/8021q/vlan_dev.c linux-2.5.65-bk2/net/8021q/vlan_dev.c
--- linux-2.5.65-bk1/net/8021q/vlan_dev.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/net/8021q/vlan_dev.c	Mon Mar 31 12:39:51 2003
@@ -785,6 +785,7 @@
 			kfree(dev->priv);
 			dev->priv = NULL;
 		}
+		kfree(dev);
 	}
 }
 
diff -urN linux-2.5.65-bk1/net/Makefile linux-2.5.65-bk2/net/Makefile
--- linux-2.5.65-bk1/net/Makefile	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/net/Makefile	Mon Mar 31 12:39:51 2003
@@ -5,7 +5,9 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-obj-y	:= socket.o core/
+obj-y	:= nonet.o
+
+obj-$(CONFIG_NET)		:= socket.o core/
 
 obj-$(CONFIG_COMPAT)		+= compat.o
 
diff -urN linux-2.5.65-bk1/net/atm/pppoatm.c linux-2.5.65-bk2/net/atm/pppoatm.c
--- linux-2.5.65-bk1/net/atm/pppoatm.c	Mon Mar 17 13:44:19 2003
+++ linux-2.5.65-bk2/net/atm/pppoatm.c	Mon Mar 31 12:39:51 2003
@@ -231,7 +231,7 @@
 		kfree_skb(skb);
 		return 1;
 	}
-	atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->tx_inuse);
+	atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->wmem_alloc);
 	ATM_SKB(skb)->iovcnt = 0;
 	ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
 	DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n",
diff -urN linux-2.5.65-bk1/net/bridge/netfilter/ebt_ip.c linux-2.5.65-bk2/net/bridge/netfilter/ebt_ip.c
--- linux-2.5.65-bk1/net/bridge/netfilter/ebt_ip.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/net/bridge/netfilter/ebt_ip.c	Mon Mar 31 12:39:51 2003
@@ -86,7 +86,7 @@
 	if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
 		return -EINVAL;
 	if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) {
-		if (!(info->bitmask & EBT_IPROTO))
+		if (info->bitmask & EBT_IPROTO)
 			return -EINVAL;
 		if (info->protocol != IPPROTO_TCP &&
 		    info->protocol != IPPROTO_UDP)
diff -urN linux-2.5.65-bk1/net/core/datagram.c linux-2.5.65-bk2/net/core/datagram.c
--- linux-2.5.65-bk1/net/core/datagram.c	Mon Mar 17 13:44:11 2003
+++ linux-2.5.65-bk2/net/core/datagram.c	Mon Mar 31 12:39:51 2003
@@ -68,11 +68,9 @@
 static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
 {
 	int error;
+	DEFINE_WAIT(wait);
 
-	DECLARE_WAITQUEUE(wait, current);
-
-	__set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue_exclusive(sk->sleep, &wait);
+	prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 
 	/* Socket errors? */
 	error = sock_error(sk);
@@ -101,8 +99,7 @@
 	error = 0;
 	*timeo_p = schedule_timeout(*timeo_p);
 out:
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk->sleep, &wait);
+	finish_wait(sk->sleep, &wait);
 	return error;
 interrupted:
 	error = sock_intr_errno(*timeo_p);
diff -urN linux-2.5.65-bk1/net/core/dev.c linux-2.5.65-bk2/net/core/dev.c
--- linux-2.5.65-bk1/net/core/dev.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/net/core/dev.c	Mon Mar 31 12:39:51 2003
@@ -547,6 +547,50 @@
 }
 
 /**
+ *	dev_get_by_flags - find any device with given flags
+ *	@if_flags: IFF_* values
+ *	@mask: bitmask of bits in if_flags to check
+ *
+ *	Search for any interface with the given flags. Returns NULL if a device
+ *	is not found or a pointer to the device. The device returned has 
+ *	had a reference added and the pointer is safe until the user calls
+ *	dev_put to indicate they have finished with it.
+ */
+
+struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask)
+{
+	struct net_device *dev;
+
+	read_lock(&dev_base_lock);
+	dev = __dev_get_by_flags(if_flags, mask);
+	if (dev)
+		dev_hold(dev);
+	read_unlock(&dev_base_lock);
+	return dev;
+}
+
+/**
+ *	__dev_get_by_flags - find any device with given flags
+ *	@if_flags: IFF_* values
+ *	@mask: bitmask of bits in if_flags to check
+ *
+ *	Search for any interface with the given flags. Returns NULL if a device
+ *	is not found or a pointer to the device. The caller must hold either
+ *	the RTNL semaphore or @dev_base_lock.
+ */
+
+struct net_device *__dev_get_by_flags(unsigned short if_flags, unsigned short mask)
+{
+	struct net_device *dev;
+
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+		if (((dev->flags ^ if_flags) & mask) == 0)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
  *	dev_alloc_name - allocate a name for a device
  *	@dev: device
  *	@name: name format string
@@ -2595,12 +2639,10 @@
 	}
 #ifdef NET_REFCNT_DEBUG
 	printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name,
-	       (dev->features & NETIF_F_DYNALLOC)?"":", old style");
+	       (dev->destructor != NULL)?"":", old style");
 #endif
 	if (dev->destructor)
 		dev->destructor(dev);
-	if (dev->features & NETIF_F_DYNALLOC)
-		kfree(dev);
 	return 0;
 }
 
@@ -2680,7 +2722,7 @@
 	free_divert_blk(dev);
 #endif
 
-	if (dev->features & NETIF_F_DYNALLOC) {
+	if (dev->destructor != NULL) {
 #ifdef NET_REFCNT_DEBUG
 		if (atomic_read(&dev->refcnt) != 1)
 			printk(KERN_DEBUG "unregister_netdevice: holding %s "
diff -urN linux-2.5.65-bk1/net/core/dst.c linux-2.5.65-bk2/net/core/dst.c
--- linux-2.5.65-bk1/net/core/dst.c	Mon Mar 17 13:44:10 2003
+++ linux-2.5.65-bk2/net/core/dst.c	Mon Mar 31 12:39:51 2003
@@ -228,7 +228,7 @@
 				   _race_ _condition_.
 				 */
 				if (event!=NETDEV_DOWN &&
-				    !(dev->features & NETIF_F_DYNALLOC) &&
+				    dev->destructor == NULL &&
 				    dst->output == dst_blackhole) {
 					dst->dev = &loopback_dev;
 					dev_put(dev);
diff -urN linux-2.5.65-bk1/net/core/skbuff.c linux-2.5.65-bk2/net/core/skbuff.c
--- linux-2.5.65-bk1/net/core/skbuff.c	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/net/core/skbuff.c	Mon Mar 31 12:39:51 2003
@@ -208,6 +208,7 @@
 	skb->len	  = 0;
 	skb->data_len	  = 0;
 	skb->csum	  = 0;
+	skb->local_df	  = 0;
 	skb->cloned	  = 0;
 	skb->pkt_type	  = PACKET_HOST;	/* Default type */
 	skb->ip_summed	  = 0;
@@ -375,6 +376,7 @@
 	C(len);
 	C(data_len);
 	C(csum);
+	C(local_df);
 	n->cloned = 1;
 	C(pkt_type);
 	C(ip_summed);
@@ -438,6 +440,7 @@
 	new->mac.raw	= old->mac.raw + offset;
 	memcpy(new->cb, old->cb, sizeof(old->cb));
 	atomic_set(&new->users, 1);
+	new->local_df	= old->local_df;
 	new->pkt_type	= old->pkt_type;
 	new->stamp	= old->stamp;
 	new->destructor = NULL;
diff -urN linux-2.5.65-bk1/net/core/sock.c linux-2.5.65-bk2/net/core/sock.c
--- linux-2.5.65-bk1/net/core/sock.c	Mon Mar 17 13:44:22 2003
+++ linux-2.5.65-bk2/net/core/sock.c	Mon Mar 31 12:39:51 2003
@@ -746,17 +746,16 @@
  */
 static long sock_wait_for_wmem(struct sock * sk, long timeo)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
 	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
-	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
 		if (!timeo)
 			break;
 		if (signal_pending(current))
 			break;
 		set_bit(SOCK_NOSPACE, &sk->socket->flags);
-		set_current_state(TASK_INTERRUPTIBLE);
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 		if (atomic_read(&sk->wmem_alloc) < sk->sndbuf)
 			break;
 		if (sk->shutdown & SEND_SHUTDOWN)
@@ -765,8 +764,7 @@
 			break;
 		timeo = schedule_timeout(timeo);
 	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(sk->sleep, &wait);
+	finish_wait(sk->sleep, &wait);
 	return timeo;
 }
 
@@ -860,19 +858,18 @@
 
 void __lock_sock(struct sock *sk)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
-	add_wait_queue_exclusive(&sk->lock.wq, &wait);
 	for(;;) {
-		current->state = TASK_UNINTERRUPTIBLE;
+		prepare_to_wait_exclusive(&sk->lock.wq, &wait,
+					TASK_UNINTERRUPTIBLE);
 		spin_unlock_bh(&sk->lock.slock);
 		schedule();
 		spin_lock_bh(&sk->lock.slock);
 		if(!sock_owned_by_user(sk))
 			break;
 	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&sk->lock.wq, &wait);
+	finish_wait(&sk->lock.wq, &wait);
 }
 
 void __release_sock(struct sock *sk)
diff -urN linux-2.5.65-bk1/net/ipv4/af_inet.c linux-2.5.65-bk2/net/ipv4/af_inet.c
--- linux-2.5.65-bk1/net/ipv4/af_inet.c	Mon Mar 17 13:43:42 2003
+++ linux-2.5.65-bk2/net/ipv4/af_inet.c	Mon Mar 31 12:39:51 2003
@@ -562,10 +562,9 @@
 
 static long inet_wait_for_connect(struct sock *sk, long timeo)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
-	__set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(sk->sleep, &wait);
+	prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 
 	/* Basic assumption: if someone sets sk->err, he _must_
 	 * change state of the socket from TCP_SYN_*.
@@ -578,10 +577,9 @@
 		lock_sock(sk);
 		if (signal_pending(current) || !timeo)
 			break;
-		set_current_state(TASK_INTERRUPTIBLE);
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(sk->sleep, &wait);
+	finish_wait(sk->sleep, &wait);
 	return timeo;
 }
 
diff -urN linux-2.5.65-bk1/net/ipv4/ah.c linux-2.5.65-bk2/net/ipv4/ah.c
--- linux-2.5.65-bk1/net/ipv4/ah.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/net/ipv4/ah.c	Mon Mar 31 12:39:51 2003
@@ -68,8 +68,10 @@
 		char 		buf[60];
 	} tmp_iph;
 
-	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL)
-		return -EINVAL;
+	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
+		err = -EINVAL;
+		goto error_nolock;
+	}
 
 	spin_lock_bh(&x->lock);
 	if ((err = xfrm_state_check_expire(x)) != 0)
@@ -139,8 +141,10 @@
 	x->curlft.bytes += skb->len;
 	x->curlft.packets++;
 	spin_unlock_bh(&x->lock);
-	if ((skb->dst = dst_pop(dst)) == NULL)
+	if ((skb->dst = dst_pop(dst)) == NULL) {
+		err = -EHOSTUNREACH;
 		goto error_nolock;
+	}
 	return NET_XMIT_BYPASS;
 
 error:
diff -urN linux-2.5.65-bk1/net/ipv4/arp.c linux-2.5.65-bk2/net/ipv4/arp.c
--- linux-2.5.65-bk1/net/ipv4/arp.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/net/ipv4/arp.c	Mon Mar 31 12:39:51 2003
@@ -510,11 +510,11 @@
 	 */
 	
 	skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
-				+ dev->hard_header_len + 15, GFP_ATOMIC);
+				+ LL_RESERVED_SPACE(dev), GFP_ATOMIC);
 	if (skb == NULL)
 		return;
 
-	skb_reserve(skb, (dev->hard_header_len+15)&~15);
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 	skb->nh.raw = skb->data;
 	arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
 	skb->dev = dev;
diff -urN linux-2.5.65-bk1/net/ipv4/esp.c linux-2.5.65-bk2/net/ipv4/esp.c
--- linux-2.5.65-bk1/net/ipv4/esp.c	Mon Mar 17 13:44:08 2003
+++ linux-2.5.65-bk2/net/ipv4/esp.c	Mon Mar 31 12:39:51 2003
@@ -32,8 +32,10 @@
 	} tmp_iph;
 
 	/* First, if the skb is not checksummed, complete checksum. */
-	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL)
-		return -EINVAL;
+	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
+		err = -EINVAL;
+		goto error_nolock;
+	}
 
 	spin_lock_bh(&x->lock);
 	if ((err = xfrm_state_check_expire(x)) != 0)
@@ -143,8 +145,10 @@
 	x->curlft.bytes += skb->len;
 	x->curlft.packets++;
 	spin_unlock_bh(&x->lock);
-	if ((skb->dst = dst_pop(dst)) == NULL)
+	if ((skb->dst = dst_pop(dst)) == NULL) {
+		err = -EHOSTUNREACH;
 		goto error_nolock;
+	}
 	return NET_XMIT_BYPASS;
 
 error:
@@ -259,7 +263,7 @@
 	if (esp->conf.padlen)
 		mtu = (mtu + esp->conf.padlen-1)&~(esp->conf.padlen-1);
 
-	return mtu + x->props.header_len + esp->auth.icv_full_len;
+	return mtu + x->props.header_len + esp->auth.icv_trunc_len;
 }
 
 void esp4_err(struct sk_buff *skb, u32 info)
@@ -365,6 +369,7 @@
 	if (x->props.mode)
 		x->props.header_len += 20;
 	x->data = esp;
+	x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len;
 	return 0;
 
 error:
diff -urN linux-2.5.65-bk1/net/ipv4/igmp.c linux-2.5.65-bk2/net/ipv4/igmp.c
--- linux-2.5.65-bk1/net/ipv4/igmp.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/net/ipv4/igmp.c	Mon Mar 31 12:39:51 2003
@@ -211,7 +211,7 @@
 		return -1;
 	}
 
-	skb=alloc_skb(IGMP_SIZE+dev->hard_header_len+15, GFP_ATOMIC);
+	skb=alloc_skb(IGMP_SIZE+LL_RESERVED_SPACE(dev), GFP_ATOMIC);
 	if (skb == NULL) {
 		ip_rt_put(rt);
 		return -1;
@@ -219,7 +219,7 @@
 
 	skb->dst = &rt->u.dst;
 
-	skb_reserve(skb, (dev->hard_header_len+15)&~15);
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 
 	skb->nh.iph = iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)+4);
 
diff -urN linux-2.5.65-bk1/net/ipv4/ip_forward.c linux-2.5.65-bk2/net/ipv4/ip_forward.c
--- linux-2.5.65-bk1/net/ipv4/ip_forward.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/net/ipv4/ip_forward.c	Mon Mar 31 12:39:51 2003
@@ -92,7 +92,7 @@
 		goto sr_failed;
 
 	/* We are about to mangle packet. Copy it! */
-	if (skb_cow(skb, rt->u.dst.dev->hard_header_len+rt->u.dst.header_len))
+	if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))
 		goto drop;
 	iph = skb->nh.iph;
 
diff -urN linux-2.5.65-bk1/net/ipv4/ip_gre.c linux-2.5.65-bk2/net/ipv4/ip_gre.c
--- linux-2.5.65-bk1/net/ipv4/ip_gre.c	Mon Mar 17 13:44:22 2003
+++ linux-2.5.65-bk2/net/ipv4/ip_gre.c	Mon Mar 31 12:39:51 2003
@@ -273,7 +273,6 @@
 	nt = (struct ip_tunnel*)dev->priv;
 	nt->dev = dev;
 	dev->init = ipgre_tunnel_init;
-	dev->features |= NETIF_F_DYNALLOC;
 	memcpy(&nt->parms, parms, sizeof(*parms));
 	nt->parms.name[IFNAMSIZ-1] = '\0';
 	strcpy(dev->name, nt->parms.name);
@@ -305,6 +304,7 @@
 static void ipgre_tunnel_destructor(struct net_device *dev)
 {
 	if (dev != &ipgre_fb_tunnel_dev) {
+		kfree(dev);
 		MOD_DEC_USE_COUNT;
 	}
 }
@@ -824,7 +824,7 @@
 
 	skb->h.raw = skb->nh.raw;
 
-	max_headroom = ((tdev->hard_header_len+15)&~15)+ gre_hlen;
+	max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen;
 
 	if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
 		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
diff -urN linux-2.5.65-bk1/net/ipv4/ip_output.c linux-2.5.65-bk2/net/ipv4/ip_output.c
--- linux-2.5.65-bk1/net/ipv4/ip_output.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/net/ipv4/ip_output.c	Mon Mar 31 12:39:51 2003
@@ -162,13 +162,13 @@
 	struct dst_entry *dst = skb->dst;
 	struct hh_cache *hh = dst->hh;
 	struct net_device *dev = dst->dev;
+	int hh_len = LL_RESERVED_SPACE(dev);
 
 	/* Be paranoid, rather than too clever. */
-	if (unlikely(skb_headroom(skb) < dev->hard_header_len
-		     && dev->hard_header)) {
+	if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
 		struct sk_buff *skb2;
 
-		skb2 = skb_realloc_headroom(skb, (dev->hard_header_len&~15) + 16);
+		skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
 		if (skb2 == NULL) {
 			kfree_skb(skb);
 			return -ENOMEM;
@@ -440,7 +440,7 @@
 
 	iph = skb->nh.iph;
 
-	if (unlikely(iph->frag_off & htons(IP_DF))) {
+	if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
 			  htonl(dst_pmtu(&rt->u.dst)));
 		kfree_skb(skb);
@@ -572,7 +572,7 @@
 		 *	Allocate buffer.
 		 */
 
-		if ((skb2 = alloc_skb(len+hlen+rt->u.dst.dev->hard_header_len+16,GFP_ATOMIC)) == NULL) {
+		if ((skb2 = alloc_skb(len+hlen+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
 			NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n"));
 			err = -ENOMEM;
 			goto fail;
@@ -583,7 +583,7 @@
 		 */
 
 		ip_copy_metadata(skb2, skb);
-		skb_reserve(skb2, (rt->u.dst.dev->hard_header_len&~15)+16);
+		skb_reserve(skb2, LL_RESERVED_SPACE(rt->u.dst.dev));
 		skb_put(skb2, len + hlen);
 		skb2->nh.raw = skb2->data;
 		skb2->h.raw = skb2->data + hlen;
@@ -771,7 +771,7 @@
 		exthdrlen = 0;
 		mtu = inet->cork.fragsize;
 	}
-	hh_len = (rt->u.dst.dev->hard_header_len&~15) + 16;
+	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
 
 	fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
 	maxfraglen = ((mtu-fragheaderlen) & ~7) + fragheaderlen;
@@ -793,6 +793,19 @@
 
 	inet->cork.length += length;
 
+	/* So, what's going on in the loop below?
+	 *
+	 * We use calculated fragment length to generate chained skb,
+	 * each of segments is IP fragment ready for sending to network after
+	 * adding appropriate IP header.
+	 *
+	 * Mistake is:
+	 *
+	 *    If mtu-fragheaderlen is not 0 modulo 8, we generate additional
+	 *    small fragment of length (mtu-fragheaderlen)%8, even though
+	 *    it is not necessary. Not a big bug, but needs a fix.
+	 */
+
 	if ((skb = skb_peek_tail(&sk->write_queue)) == NULL)
 		goto alloc_new_skb;
 
@@ -815,6 +828,15 @@
 				alloclen = maxfraglen;
 			else
 				alloclen = datalen + fragheaderlen;
+
+			/* The last fragment gets additional space at tail.
+			 * Note, with MSG_MORE we overallocate on fragments,
+			 * because we have no idea what fragment will be
+			 * the last.
+			 */
+			if (datalen == length)
+				alloclen += rt->u.dst.trailer_len;
+
 			if (transhdrlen) {
 				skb = sock_alloc_send_skb(sk, 
 						alloclen + hh_len + 15,
@@ -967,7 +989,7 @@
 	if (!(rt->u.dst.dev->features&NETIF_F_SG))
 		return -EOPNOTSUPP;
 
-	hh_len = (rt->u.dst.dev->hard_header_len&~15)+16;
+	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
 	mtu = inet->cork.fragsize;
 
 	fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
@@ -1088,6 +1110,16 @@
 #endif
 	}
 
+	/* Unless user demanded real pmtu discovery (IP_PMTUDISC_DO), we allow
+	 * to fragment the frame generated here. No matter, what transforms
+	 * how transforms change size of the packet, it will come out.
+	 */
+	if (inet->pmtudisc != IP_PMTUDISC_DO)
+		skb->local_df = 1;
+
+	/* DF bit is set when we want to see DF on outgoing frames.
+	 * If local_df is set too, we still allow to fragment this frame
+	 * locally. */
 	if (inet->pmtudisc == IP_PMTUDISC_DO ||
 	    (!skb_shinfo(skb)->frag_list && ip_dont_fragment(sk, &rt->u.dst)))
 		df = htons(IP_DF);
diff -urN linux-2.5.65-bk1/net/ipv4/ipconfig.c linux-2.5.65-bk2/net/ipv4/ipconfig.c
--- linux-2.5.65-bk1/net/ipv4/ipconfig.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/net/ipv4/ipconfig.c	Mon Mar 31 12:39:51 2003
@@ -656,7 +656,7 @@
 	struct net_device *dev = d->dev;
 	struct sk_buff *skb;
 	struct bootp_pkt *b;
-	int hh_len = (dev->hard_header_len + 15) & ~15;
+	int hh_len = LL_RESERVED_SPACE(dev);
 	struct iphdr *h;
 
 	/* Allocate packet */
diff -urN linux-2.5.65-bk1/net/ipv4/ipip.c linux-2.5.65-bk2/net/ipv4/ipip.c
--- linux-2.5.65-bk1/net/ipv4/ipip.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/net/ipv4/ipip.c	Mon Mar 31 12:39:51 2003
@@ -242,7 +242,6 @@
 	nt = (struct ip_tunnel*)dev->priv;
 	nt->dev = dev;
 	dev->init = ipip_tunnel_init;
-	dev->features |= NETIF_F_DYNALLOC;
 	memcpy(&nt->parms, parms, sizeof(*parms));
 	nt->parms.name[IFNAMSIZ-1] = '\0';
 	strcpy(dev->name, nt->parms.name);
@@ -274,6 +273,7 @@
 static void ipip_tunnel_destructor(struct net_device *dev)
 {
 	if (dev != &ipip_fb_tunnel_dev) {
+		kfree(dev);
 		MOD_DEC_USE_COUNT;
 	}
 }
@@ -616,7 +616,7 @@
 	/*
 	 * Okay, now see if we can stuff it in the buffer as-is.
 	 */
-	max_headroom = (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr));
+	max_headroom = (LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr));
 
 	if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
 		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
diff -urN linux-2.5.65-bk1/net/ipv4/ipmr.c linux-2.5.65-bk2/net/ipv4/ipmr.c
--- linux-2.5.65-bk1/net/ipv4/ipmr.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/net/ipv4/ipmr.c	Mon Mar 31 12:39:51 2003
@@ -182,6 +182,11 @@
 	return (struct net_device_stats*)dev->priv;
 }
 
+static void vif_dev_destructor(struct net_device *dev)
+{
+	kfree(dev);
+}
+
 static
 struct net_device *ipmr_reg_vif(struct vifctl *v)
 {
@@ -205,7 +210,7 @@
 	dev->flags		= IFF_NOARP;
 	dev->hard_start_xmit	= reg_vif_xmit;
 	dev->get_stats		= reg_vif_get_stats;
-	dev->features		|= NETIF_F_DYNALLOC;
+	dev->destructor		= vif_dev_destructor;
 
 	if (register_netdevice(dev)) {
 		kfree(dev);
@@ -1178,7 +1183,7 @@
 		return;
 	}
 
-	encap += dev->hard_header_len;
+	encap += LL_RESERVED_SPACE(dev);
 
 	if (skb_headroom(skb) < encap || skb_cloned(skb) || !last)
 		skb2 = skb_realloc_headroom(skb, (encap + 15)&~15);
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/arp_tables.c linux-2.5.65-bk2/net/ipv4/netfilter/arp_tables.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/arp_tables.c	Mon Mar 17 13:44:38 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/arp_tables.c	Mon Mar 31 12:39:51 2003
@@ -1205,14 +1205,24 @@
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct arpt_target arpt_standard_target
-= { { NULL, NULL }, ARPT_STANDARD_TARGET, NULL, NULL, NULL };
-static struct arpt_target arpt_error_target
-= { { NULL, NULL }, ARPT_ERROR_TARGET, arpt_error, NULL, NULL };
+static struct arpt_target arpt_standard_target = {
+	.name		= ARPT_STANDARD_TARGET,
+};
 
-static struct nf_sockopt_ops arpt_sockopts
-= { { NULL, NULL }, PF_INET, ARPT_BASE_CTL, ARPT_SO_SET_MAX+1, do_arpt_set_ctl,
-    ARPT_BASE_CTL, ARPT_SO_GET_MAX+1, do_arpt_get_ctl, 0, NULL  };
+static struct arpt_target arpt_error_target = {
+	.name		= ARPT_ERROR_TARGET,
+	.target		= arpt_error,
+};
+
+static struct nf_sockopt_ops arpt_sockopts = {
+	.pf		= PF_INET,
+	.set_optmin	= ARPT_BASE_CTL,
+	.set_optmax	= ARPT_SO_SET_MAX+1,
+	.set		= do_arpt_set_ctl,
+	.get_optmin	= ARPT_BASE_CTL,
+	.get_optmax	= ARPT_SO_GET_MAX+1,
+	.get		= do_arpt_get_ctl,
+};
 
 #ifdef CONFIG_PROC_FS
 static inline int print_name(const struct arpt_table *t,
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ip_conntrack_core.c linux-2.5.65-bk2/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ip_conntrack_core.c	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ip_conntrack_core.c	Mon Mar 31 12:39:51 2003
@@ -1339,11 +1339,12 @@
 	return -ENOENT;
 }
 
-static struct nf_sockopt_ops so_getorigdst
-= { { NULL, NULL }, PF_INET,
-    0, 0, NULL, /* Setsockopts */
-    SO_ORIGINAL_DST, SO_ORIGINAL_DST+1, &getorigdst,
-    0, NULL };
+static struct nf_sockopt_ops so_getorigdst = {
+	.pf		= PF_INET,
+	.get_optmin	= SO_ORIGINAL_DST,
+	.get_optmax	= SO_ORIGINAL_DST+1,
+	.get		= &getorigdst,
+};
 
 #define NET_IP_CONNTRACK_MAX 2089
 #define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max"
@@ -1367,7 +1368,6 @@
 	{
 		.ctl_name	= NET_IPV4,
 		.procname	= "ipv4",
-		.maxlen		= 0,
 		.mode		= 0555,
 		.child		= ip_conntrack_table
 	},
@@ -1378,7 +1378,6 @@
 	{
 		.ctl_name	= CTL_NET,
 		.procname	= "net",
-		.maxlen		= 0,
 		.mode		= 0555,
 		.child		= ip_conntrack_dir_table
 	},
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ip_queue.c linux-2.5.65-bk2/net/ipv4/netfilter/ip_queue.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ip_queue.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ip_queue.c	Mon Mar 31 12:39:51 2003
@@ -555,9 +555,7 @@
 }
 
 static struct notifier_block ipq_dev_notifier = {
-	ipq_rcv_dev_event,
-	NULL,
-	0
+	.notifier_call	= ipq_rcv_dev_event,
 };
 
 static int
@@ -577,9 +575,7 @@
 }
 
 static struct notifier_block ipq_nl_notifier = {
-	ipq_rcv_nl_event,
-	NULL,
-	0
+	.notifier_call	= ipq_rcv_nl_event,
 };
 
 static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
@@ -601,7 +597,6 @@
 	{
 		.ctl_name	= NET_IPV4,
 		.procname	= "ipv4",
-		.maxlen		= 0,
 		.mode		= 0555,
 		.child		= ipq_table
 	},
@@ -612,7 +607,6 @@
 	{
 		.ctl_name	= CTL_NET,
 		.procname	= "net",
-		.maxlen		= 0,
 		.mode		= 0555,
 		.child		= ipq_dir_table
 	},
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ip_tables.c linux-2.5.65-bk2/net/ipv4/netfilter/ip_tables.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ip_tables.c	Mon Mar 17 13:43:48 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ip_tables.c	Mon Mar 31 12:39:51 2003
@@ -1663,21 +1663,42 @@
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct ipt_target ipt_standard_target
-= { { NULL, NULL }, IPT_STANDARD_TARGET, NULL, NULL, NULL };
-static struct ipt_target ipt_error_target
-= { { NULL, NULL }, IPT_ERROR_TARGET, ipt_error, NULL, NULL };
-
-static struct nf_sockopt_ops ipt_sockopts
-= { { NULL, NULL }, PF_INET, IPT_BASE_CTL, IPT_SO_SET_MAX+1, do_ipt_set_ctl,
-    IPT_BASE_CTL, IPT_SO_GET_MAX+1, do_ipt_get_ctl, 0, NULL  };
-
-static struct ipt_match tcp_matchstruct
-= { { NULL, NULL }, "tcp", &tcp_match, &tcp_checkentry, NULL };
-static struct ipt_match udp_matchstruct
-= { { NULL, NULL }, "udp", &udp_match, &udp_checkentry, NULL };
-static struct ipt_match icmp_matchstruct
-= { { NULL, NULL }, "icmp", &icmp_match, &icmp_checkentry, NULL };
+static struct ipt_target ipt_standard_target = {
+	.name		= IPT_STANDARD_TARGET,
+};
+
+static struct ipt_target ipt_error_target = {
+	.name		= IPT_ERROR_TARGET,
+	.target		= ipt_error,
+};
+
+static struct nf_sockopt_ops ipt_sockopts = {
+	.pf		= PF_INET,
+	.set_optmin	= IPT_BASE_CTL,
+	.set_optmax	= IPT_SO_SET_MAX+1,
+	.set		= do_ipt_set_ctl,
+	.get_optmin	= IPT_BASE_CTL,
+	.get_optmax	= IPT_SO_GET_MAX+1,
+	.get		= do_ipt_get_ctl,
+};
+
+static struct ipt_match tcp_matchstruct = {
+	.name		= "tcp",
+	.match		= &tcp_match,
+	.checkentry	= &tcp_checkentry,
+};
+
+static struct ipt_match udp_matchstruct = {
+	.name		= "udp",
+	.match		= &udp_match,
+	.checkentry	= &udp_checkentry,
+};
+
+static struct ipt_match icmp_matchstruct = {
+	.name		= "icmp",
+	.match		= &icmp_match,
+	.checkentry	= &icmp_checkentry,
+};
 
 #ifdef CONFIG_PROC_FS
 static inline int print_name(const struct ipt_table *t,
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipfwadm_core.c linux-2.5.65-bk2/net/ipv4/netfilter/ipfwadm_core.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipfwadm_core.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipfwadm_core.c	Mon Mar 31 12:39:51 2003
@@ -1315,9 +1315,7 @@
 }
 
 static struct notifier_block ipfw_dev_notifier={
-	ipfw_device_event,
-	NULL,
-	0
+	.notifier_call	= ipfw_device_event,
 };
 
 #endif
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_DSCP.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_DSCP.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_DSCP.c	Mon Mar 17 13:44:45 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_DSCP.c	Mon Mar 31 12:39:51 2003
@@ -88,8 +88,12 @@
 	return 1;
 }
 
-static struct ipt_target ipt_dscp_reg
-= { { NULL, NULL }, "DSCP", target, checkentry, NULL, THIS_MODULE };
+static struct ipt_target ipt_dscp_reg = {
+	.name		= "DSCP",
+	.target		= target,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ECN.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ECN.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ECN.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ECN.c	Mon Mar 31 12:39:51 2003
@@ -164,8 +164,12 @@
 	return 1;
 }
 
-static struct ipt_target ipt_ecn_reg
-= { { NULL, NULL }, "ECN", target, checkentry, NULL, THIS_MODULE };
+static struct ipt_target ipt_ecn_reg = {
+	.name		= "ECN",
+	.target		= target,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_LOG.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_LOG.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_LOG.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_LOG.c	Mon Mar 31 12:39:51 2003
@@ -350,9 +350,12 @@
 	return 1;
 }
 
-static struct ipt_target ipt_log_reg
-= { { NULL, NULL }, "LOG", ipt_log_target, ipt_log_checkentry, NULL, 
-    THIS_MODULE };
+static struct ipt_target ipt_log_reg = {
+	.name		= "LOG",
+	.target		= ipt_log_target,
+	.checkentry	= ipt_log_checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_MARK.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_MARK.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_MARK.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_MARK.c	Mon Mar 31 12:39:51 2003
@@ -46,8 +46,12 @@
 	return 1;
 }
 
-static struct ipt_target ipt_mark_reg
-= { { NULL, NULL }, "MARK", target, checkentry, NULL, THIS_MODULE };
+static struct ipt_target ipt_mark_reg = {
+	.name		= "MARK",
+	.target		= target,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_MASQUERADE.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_MASQUERADE.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_MASQUERADE.c	Mon Mar 17 13:44:12 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_MASQUERADE.c	Mon Mar 31 12:39:51 2003
@@ -167,20 +167,19 @@
 }
 
 static struct notifier_block masq_dev_notifier = {
-	masq_device_event,
-	NULL,
-	0
+	.notifier_call	= masq_device_event,
 };
 
 static struct notifier_block masq_inet_notifier = {
-	masq_inet_event,
-	NULL,
-	0
+	.notifier_call	= masq_inet_event,
 };
 
-static struct ipt_target masquerade
-= { { NULL, NULL }, "MASQUERADE", masquerade_target, masquerade_check, NULL,
-    THIS_MODULE };
+static struct ipt_target masquerade = {
+	.name		= "MASQUERADE",
+	.target		= masquerade_target,
+	.checkentry	= masquerade_check,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_MIRROR.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_MIRROR.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_MIRROR.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_MIRROR.c	Mon Mar 31 12:39:51 2003
@@ -157,9 +157,12 @@
 	return 1;
 }
 
-static struct ipt_target ipt_mirror_reg
-= { { NULL, NULL }, "MIRROR", ipt_mirror_target, ipt_mirror_checkentry, NULL,
-    THIS_MODULE };
+static struct ipt_target ipt_mirror_reg = {
+	.name		= "MIRROR",
+	.target		= ipt_mirror_target,
+	.checkentry	= ipt_mirror_checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_REDIRECT.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_REDIRECT.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_REDIRECT.c	Mon Mar 17 13:44:02 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_REDIRECT.c	Mon Mar 31 12:39:51 2003
@@ -96,9 +96,12 @@
 	return ip_nat_setup_info(ct, &newrange, hooknum);
 }
 
-static struct ipt_target redirect_reg
-= { { NULL, NULL }, "REDIRECT", redirect_target, redirect_check, NULL,
-    THIS_MODULE };
+static struct ipt_target redirect_reg = {
+	.name		= "REDIRECT",
+	.target		= redirect_target,
+	.checkentry	= redirect_check,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_REJECT.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_REJECT.c	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_REJECT.c	Mon Mar 31 12:39:51 2003
@@ -386,8 +386,12 @@
 	return 1;
 }
 
-static struct ipt_target ipt_reject_reg
-= { { NULL, NULL }, "REJECT", reject, check, NULL, THIS_MODULE };
+static struct ipt_target ipt_reject_reg = {
+	.name		= "REJECT",
+	.target		= reject,
+	.checkentry	= check,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_TCPMSS.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_TCPMSS.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_TCPMSS.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_TCPMSS.c	Mon Mar 31 12:39:51 2003
@@ -238,9 +238,12 @@
 	return 0;
 }
 
-static struct ipt_target ipt_tcpmss_reg
-= { { NULL, NULL }, "TCPMSS",
-    ipt_tcpmss_target, ipt_tcpmss_checkentry, NULL, THIS_MODULE };
+static struct ipt_target ipt_tcpmss_reg = {
+	.name		= "TCPMSS",
+	.target		= ipt_tcpmss_target,
+	.checkentry	= ipt_tcpmss_checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_TOS.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_TOS.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_TOS.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_TOS.c	Mon Mar 31 12:39:51 2003
@@ -76,8 +76,12 @@
 	return 1;
 }
 
-static struct ipt_target ipt_tos_reg
-= { { NULL, NULL }, "TOS", target, checkentry, NULL, THIS_MODULE };
+static struct ipt_target ipt_tos_reg = {
+	.name		= "TOS",
+	.target		= target,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ULOG.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ULOG.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ULOG.c	Mon Mar 17 13:44:02 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ULOG.c	Mon Mar 31 12:39:51 2003
@@ -304,9 +304,11 @@
 	return 1;
 }
 
-static struct ipt_target ipt_ulog_reg =
-    { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL,
-THIS_MODULE
+static struct ipt_target ipt_ulog_reg = {
+	.name		= "ULOG",
+	.target		= ipt_ulog_target,
+	.checkentry	= ipt_ulog_checkentry,
+	.me		= THIS_MODULE,
 };
 
 static int __init init(void)
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ah.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ah.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ah.c	Mon Mar 17 13:44:15 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ah.c	Mon Mar 31 12:39:51 2003
@@ -87,8 +87,12 @@
 	return 1;
 }
 
-static struct ipt_match ah_match
-= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match ah_match = {
+	.name		= "ah",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_conntrack.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_conntrack.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_conntrack.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_conntrack.c	Mon Mar 31 12:39:51 2003
@@ -100,8 +100,12 @@
 	return 1;
 }
 
-static struct ipt_match conntrack_match
-= { { NULL, NULL }, "conntrack", &match, &check, NULL, THIS_MODULE };
+static struct ipt_match conntrack_match = {
+	.name		= "conntrack",
+	.match		= &match,
+	.checkentry	= &check,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_dscp.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_dscp.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_dscp.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_dscp.c	Mon Mar 31 12:39:51 2003
@@ -40,8 +40,12 @@
 	return 1;
 }
 
-static struct ipt_match dscp_match = { { NULL, NULL }, "dscp", &match,
-		&checkentry, NULL, THIS_MODULE };
+static struct ipt_match dscp_match = {
+	.name		= "dscp",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ecn.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ecn.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ecn.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ecn.c	Mon Mar 31 12:39:51 2003
@@ -101,8 +101,12 @@
 	return 1;
 }
 
-static struct ipt_match ecn_match = { { NULL, NULL }, "ecn", &match,
-		&checkentry, NULL, THIS_MODULE };
+static struct ipt_match ecn_match = {
+	.name		= "ecn",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_esp.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_esp.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_esp.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_esp.c	Mon Mar 31 12:39:51 2003
@@ -87,8 +87,12 @@
 	return 1;
 }
 
-static struct ipt_match esp_match
-= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match esp_match = {
+	.name		= "esp",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_helper.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_helper.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_helper.c	Mon Mar 17 13:44:22 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_helper.c	Mon Mar 31 12:39:51 2003
@@ -89,8 +89,12 @@
 	return 1;
 }
 
-static struct ipt_match helper_match
-= { { NULL, NULL }, "helper", &match, &check, NULL, THIS_MODULE };
+static struct ipt_match helper_match = {
+	.name		= "helper",
+	.match		= &match,
+	.checkentry	= &check,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_length.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_length.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_length.c	Mon Mar 17 13:44:22 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_length.c	Mon Mar 31 12:39:51 2003
@@ -38,8 +38,12 @@
 	return 1;
 }
 
-static struct ipt_match length_match
-= { { NULL, NULL }, "length", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match length_match = {
+	.name		= "length",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_limit.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_limit.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_limit.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_limit.c	Mon Mar 31 12:39:51 2003
@@ -115,9 +115,12 @@
 	return 1;
 }
 
-static struct ipt_match ipt_limit_reg
-= { { NULL, NULL }, "limit", ipt_limit_match, ipt_limit_checkentry, NULL,
-    THIS_MODULE };
+static struct ipt_match ipt_limit_reg = {
+	.name		= "limit",
+	.match		= ipt_limit_match,
+	.checkentry	= ipt_limit_checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_mac.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_mac.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_mac.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_mac.c	Mon Mar 31 12:39:51 2003
@@ -47,8 +47,12 @@
 	return 1;
 }
 
-static struct ipt_match mac_match
-= { { NULL, NULL }, "mac", &match, &ipt_mac_checkentry, NULL, THIS_MODULE };
+static struct ipt_match mac_match = {
+	.name		= "mac",
+	.match		= &match,
+	.checkentry	= &ipt_mac_checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_mark.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_mark.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_mark.c	Mon Mar 17 13:44:52 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_mark.c	Mon Mar 31 12:39:51 2003
@@ -33,8 +33,12 @@
 	return 1;
 }
 
-static struct ipt_match mark_match
-= { { NULL, NULL }, "mark", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match mark_match = {
+	.name		= "mark",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_multiport.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_multiport.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_multiport.c	Mon Mar 17 13:43:44 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_multiport.c	Mon Mar 31 12:39:51 2003
@@ -86,8 +86,12 @@
 		&& multiinfo->count <= IPT_MULTI_PORTS;
 }
 
-static struct ipt_match multiport_match
-= { { NULL, NULL }, "multiport", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match multiport_match = {
+	.name		= "multiport",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_owner.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_owner.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_owner.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_owner.c	Mon Mar 31 12:39:51 2003
@@ -176,8 +176,12 @@
 	return 1;
 }
 
-static struct ipt_match owner_match
-= { { NULL, NULL }, "owner", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match owner_match = {
+	.name		= "owner",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_physdev.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_physdev.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_physdev.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_physdev.c	Mon Mar 31 12:39:51 2003
@@ -63,8 +63,12 @@
 	return 1;
 }
 
-static struct ipt_match physdev_match
-= { { NULL, NULL }, "physdev", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match physdev_match = {
+	.name		= "physdev",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_pkttype.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_pkttype.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_pkttype.c	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_pkttype.c	Mon Mar 31 12:39:51 2003
@@ -42,8 +42,12 @@
 	return 1;
 }
 
-static struct ipt_match pkttype_match
-= { { NULL, NULL }, "pkttype", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match pkttype_match = {
+	.name		= "pkttype",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_state.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_state.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_state.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_state.c	Mon Mar 31 12:39:51 2003
@@ -41,8 +41,12 @@
 	return 1;
 }
 
-static struct ipt_match state_match
-= { { NULL, NULL }, "state", &match, &check, NULL, THIS_MODULE };
+static struct ipt_match state_match = {
+	.name		= "state",
+	.match		= &match,
+	.checkentry	= &check,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_tcpmss.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_tcpmss.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_tcpmss.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_tcpmss.c	Mon Mar 31 12:39:51 2003
@@ -91,8 +91,12 @@
 	return 1;
 }
 
-static struct ipt_match tcpmss_match
-= { { NULL, NULL }, "tcpmss", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match tcpmss_match = {
+	.name		= "tcpmss",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_tos.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_tos.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_tos.c	Mon Mar 17 13:44:46 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_tos.c	Mon Mar 31 12:39:51 2003
@@ -34,8 +34,12 @@
 	return 1;
 }
 
-static struct ipt_match tos_match
-= { { NULL, NULL }, "tos", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match tos_match = {
+	.name		= "tos",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ttl.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ttl.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_ttl.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_ttl.c	Mon Mar 31 12:39:51 2003
@@ -57,8 +57,12 @@
 	return 1;
 }
 
-static struct ipt_match ttl_match = { { NULL, NULL }, "ttl", &match,
-		&checkentry, NULL, THIS_MODULE };
+static struct ipt_match ttl_match = {
+	.name		= "ttl",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/netfilter/ipt_unclean.c linux-2.5.65-bk2/net/ipv4/netfilter/ipt_unclean.c
--- linux-2.5.65-bk1/net/ipv4/netfilter/ipt_unclean.c	Mon Mar 17 13:44:10 2003
+++ linux-2.5.65-bk2/net/ipv4/netfilter/ipt_unclean.c	Mon Mar 31 12:39:51 2003
@@ -580,8 +580,12 @@
 	return 1;
 }
 
-static struct ipt_match unclean_match
-= { { NULL, NULL }, "unclean", &match, &checkentry, NULL, THIS_MODULE };
+static struct ipt_match unclean_match = {
+	.name		= "unclean",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv4/raw.c linux-2.5.65-bk2/net/ipv4/raw.c
--- linux-2.5.65-bk1/net/ipv4/raw.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/net/ipv4/raw.c	Mon Mar 31 12:39:51 2003
@@ -280,7 +280,7 @@
 	if (flags&MSG_PROBE)
 		goto out;
 
-	hh_len = (rt->u.dst.dev->hard_header_len&~15) + 16;
+	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
 
 	skb = sock_alloc_send_skb(sk, length+hh_len+15,
 				  flags&MSG_DONTWAIT, &err);
diff -urN linux-2.5.65-bk1/net/ipv4/tcp.c linux-2.5.65-bk2/net/ipv4/tcp.c
--- linux-2.5.65-bk1/net/ipv4/tcp.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/net/ipv4/tcp.c	Mon Mar 31 12:39:51 2003
@@ -659,7 +659,7 @@
 {
 	struct tcp_opt *tp = tcp_sk(sk);
 	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
+	DEFINE_WAIT(wait);
 
 	while ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
 		if (sk->err)
@@ -671,16 +671,14 @@
 		if (signal_pending(tsk))
 			return sock_intr_errno(*timeo_p);
 
-		__set_task_state(tsk, TASK_INTERRUPTIBLE);
-		add_wait_queue(sk->sleep, &wait);
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 		tp->write_pending++;
 
 		release_sock(sk);
 		*timeo_p = schedule_timeout(*timeo_p);
 		lock_sock(sk);
 
-		__set_task_state(tsk, TASK_RUNNING);
-		remove_wait_queue(sk->sleep, &wait);
+		finish_wait(sk->sleep, &wait);
 		tp->write_pending--;
 	}
 	return 0;
@@ -700,16 +698,15 @@
 	int err = 0;
 	long vm_wait = 0;
 	long current_timeo = *timeo;
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
 	if (tcp_memory_free(sk))
 		current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2;
 
-	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
 		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 
-		set_current_state(TASK_INTERRUPTIBLE);
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 
 		if (sk->err || (sk->shutdown & SEND_SHUTDOWN))
 			goto do_error;
@@ -740,8 +737,7 @@
 		*timeo = current_timeo;
 	}
 out:
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk->sleep, &wait);
+	finish_wait(sk->sleep, &wait);
 	return err;
 
 do_error:
@@ -1374,11 +1370,9 @@
 
 static long tcp_data_wait(struct sock *sk, long timeo)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
-	add_wait_queue(sk->sleep, &wait);
-
-	__set_current_state(TASK_INTERRUPTIBLE);
+	prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 
 	set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 	release_sock(sk);
@@ -1389,8 +1383,7 @@
 	lock_sock(sk);
 	clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 
-	remove_wait_queue(sk->sleep, &wait);
-	__set_current_state(TASK_RUNNING);
+	finish_wait(sk->sleep, &wait);
 	return timeo;
 }
 
@@ -2017,12 +2010,10 @@
 
 	if (timeout) {
 		struct task_struct *tsk = current;
-		DECLARE_WAITQUEUE(wait, current);
-
-		add_wait_queue(sk->sleep, &wait);
+		DEFINE_WAIT(wait);
 
 		do {
-			set_current_state(TASK_INTERRUPTIBLE);
+			prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 			if (!closing(sk))
 				break;
 			release_sock(sk);
@@ -2030,8 +2021,7 @@
 			lock_sock(sk);
 		} while (!signal_pending(tsk) && timeout);
 
-		tsk->state = TASK_RUNNING;
-		remove_wait_queue(sk->sleep, &wait);
+		finish_wait(sk->sleep, &wait);
 	}
 
 adjudge_to_death:
@@ -2191,7 +2181,7 @@
 static int wait_for_connect(struct sock *sk, long timeo)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 	int err;
 
 	/*
@@ -2208,9 +2198,8 @@
 	 * our exclusiveness temporarily when we get woken up without
 	 * having to remove and re-insert us on the wait queue.
 	 */
-	add_wait_queue_exclusive(sk->sleep, &wait);
 	for (;;) {
-		current->state = TASK_INTERRUPTIBLE;
+		prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 		release_sock(sk);
 		if (!tp->accept_queue)
 			timeo = schedule_timeout(timeo);
@@ -2228,8 +2217,7 @@
 		if (!timeo)
 			break;
 	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk->sleep, &wait);
+	finish_wait(sk->sleep, &wait);
 	return err;
 }
 
diff -urN linux-2.5.65-bk1/net/ipv4/tcp_ipv4.c linux-2.5.65-bk2/net/ipv4/tcp_ipv4.c
--- linux-2.5.65-bk1/net/ipv4/tcp_ipv4.c	Mon Mar 17 13:44:01 2003
+++ linux-2.5.65-bk2/net/ipv4/tcp_ipv4.c	Mon Mar 31 12:39:51 2003
@@ -334,11 +334,11 @@
 	write_lock(&tcp_lhash_lock);
 
 	if (atomic_read(&tcp_lhash_users)) {
-		DECLARE_WAITQUEUE(wait, current);
+		DEFINE_WAIT(wait);
 
-		add_wait_queue_exclusive(&tcp_lhash_wait, &wait);
 		for (;;) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
+			prepare_to_wait_exclusive(&tcp_lhash_wait,
+						&wait, TASK_UNINTERRUPTIBLE);
 			if (!atomic_read(&tcp_lhash_users))
 				break;
 			write_unlock_bh(&tcp_lhash_lock);
@@ -346,8 +346,7 @@
 			write_lock_bh(&tcp_lhash_lock);
 		}
 
-		__set_current_state(TASK_RUNNING);
-		remove_wait_queue(&tcp_lhash_wait, &wait);
+		finish_wait(&tcp_lhash_wait, &wait);
 	}
 }
 
@@ -853,11 +852,7 @@
 	/* OK, now commit destination to socket.  */
 	__sk_dst_set(sk, &rt->u.dst);
 	tcp_v4_setup_caps(sk, &rt->u.dst);
-
-	/* DAVEM REDPEN: This used to sit above forced ext_header_len = 0
-	 *               above, it was real bug.  Is this one correct?
-	 */
-	tp->ext_header_len += rt->u.dst.header_len;
+	tp->ext2_header_len = rt->u.dst.header_len;
 
 	if (!tp->write_seq)
 		tp->write_seq = secure_tcp_sequence_number(inet->saddr,
@@ -868,6 +863,7 @@
 	inet->id = tp->write_seq ^ jiffies;
 
 	err = tcp_connect(sk);
+	rt = NULL;
 	if (err)
 		goto failure;
 
@@ -1611,7 +1607,7 @@
 	newtp->ext_header_len = 0;
 	if (newinet->opt)
 		newtp->ext_header_len = newinet->opt->optlen;
-	newtp->ext_header_len += dst->header_len;
+	newtp->ext2_header_len = dst->header_len;
 	newinet->id = newtp->write_seq ^ jiffies;
 
 	tcp_sync_mss(newsk, dst_pmtu(dst));
diff -urN linux-2.5.65-bk1/net/ipv4/tcp_output.c linux-2.5.65-bk2/net/ipv4/tcp_output.c
--- linux-2.5.65-bk1/net/ipv4/tcp_output.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/net/ipv4/tcp_output.c	Mon Mar 31 12:39:51 2003
@@ -570,7 +570,7 @@
 		mss_now = tp->mss_clamp;
 
 	/* Now subtract optional transport overhead */
-	mss_now -= tp->ext_header_len;
+	mss_now -= tp->ext_header_len + tp->ext2_header_len;
 
 	/* Then reserve room for full set of TCP options and 8 bytes of data */
 	if (mss_now < 48)
@@ -591,7 +591,7 @@
 		int large_mss;
 
 		large_mss = 65535 - tp->af_specific->net_header_len -
-			tp->ext_header_len - tp->tcp_header_len;
+			tp->ext_header_len - tp->ext2_header_len - tp->tcp_header_len;
 
 		if (tp->max_window && large_mss > (tp->max_window>>1))
 			large_mss = max((tp->max_window>>1), 68U - tp->tcp_header_len);
diff -urN linux-2.5.65-bk1/net/ipv4/xfrm_policy.c linux-2.5.65-bk2/net/ipv4/xfrm_policy.c
--- linux-2.5.65-bk1/net/ipv4/xfrm_policy.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/net/ipv4/xfrm_policy.c	Mon Mar 31 12:39:51 2003
@@ -347,6 +347,7 @@
 	struct xfrm_policy *xp = (struct xfrm_policy*)data;
 	unsigned long now = (unsigned long)xtime.tv_sec;
 	long next = LONG_MAX;
+	u32 index;
 
 	if (xp->dead)
 		goto out;
@@ -368,10 +369,11 @@
 	return;
 
 expired:
+	index = xp->index;
 	xfrm_pol_put(xp);
 
 	/* Not 100% correct. id can be recycled in theory */
-	xp = xfrm_policy_byid(0, xp->index, 1);
+	xp = xfrm_policy_byid(0, index, 1);
 	if (xp) {
 		xfrm_policy_kill(xp);
 		xfrm_pol_put(xp);
@@ -894,6 +896,7 @@
 	int i;
 	int err;
 	int header_len = 0;
+	int trailer_len = 0;
 
 	dst = dst_prev = NULL;
 
@@ -919,6 +922,7 @@
 			local  = xfrm[i]->props.saddr.xfrm4_addr;
 		}
 		header_len += xfrm[i]->props.header_len;
+		trailer_len += xfrm[i]->props.trailer_len;
 	}
 
 	if (remote != fl->fl4_dst) {
@@ -945,6 +949,7 @@
 		dst_prev->flags	       |= DST_HOST;
 		dst_prev->lastuse	= jiffies;
 		dst_prev->header_len	= header_len;
+		dst_prev->trailer_len	= trailer_len;
 		memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
 		dst_prev->path		= &rt->u.dst;
 
@@ -964,6 +969,7 @@
 		x->u.rt.rt_gateway = rt->rt_gateway;
 		x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
 		header_len -= x->u.dst.xfrm->props.header_len;
+		trailer_len -= x->u.dst.xfrm->props.trailer_len;
 	}
 	*dst_p = dst;
 	return 0;
@@ -987,6 +993,7 @@
 	int i;
 	int err = 0;
 	int header_len = 0;
+	int trailer_len = 0;
 
 	dst = dst_prev = NULL;
 
@@ -1012,6 +1019,7 @@
 			local  = (struct in6_addr*)&xfrm[i]->props.saddr;
 		}
 		header_len += xfrm[i]->props.header_len;
+		trailer_len += xfrm[i]->props.trailer_len;
 	}
 
 	if (ipv6_addr_cmp(remote, fl->fl6_dst)) {
@@ -1038,6 +1046,7 @@
 		dst_prev->flags	       |= DST_HOST;
 		dst_prev->lastuse	= jiffies;
 		dst_prev->header_len	= header_len;
+		dst_prev->trailer_len	= trailer_len;
 		memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
 		dst_prev->path		= &rt->u.dst;
 
@@ -1054,6 +1063,7 @@
 		x->u.rt6.rt6i_gateway  = rt0->rt6i_gateway;
 		memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); 
 		header_len -= x->u.dst.xfrm->props.header_len;
+		trailer_len -= x->u.dst.xfrm->props.trailer_len;
 	}
 	*dst_p = dst;
 	return 0;
@@ -1082,6 +1092,17 @@
 	u32 genid;
 	u16 family = (*dst_p)->ops->family;
 
+	switch (family) {
+	case AF_INET:
+		if (!fl->fl4_src)
+			fl->fl4_src = rt->rt_src;
+		if (!fl->fl4_dst)
+			fl->fl4_dst = rt->rt_dst;
+	case AF_INET6:
+		/* Still not clear... */
+	default:
+	}
+
 restart:
 	genid = xfrm_policy_genid;
 	policy = NULL;
@@ -1120,8 +1141,6 @@
 		 * is required only for output policy.
 		 */
 		if (family == AF_INET) {
-			fl->oif = rt->u.dst.dev->ifindex;
-			fl->fl4_src = rt->rt_src;
 			read_lock_bh(&policy->lock);
 			for (dst = policy->bundles; dst; dst = dst->next) {
 				struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
@@ -1451,10 +1470,11 @@
 	if (pol->action == XFRM_POLICY_ALLOW) {
 		if (pol->xfrm_nr != 0) {
 			struct sec_path *sp;
+			static struct sec_path dummy;
 			int i, k;
 
 			if ((sp = skb->sp) == NULL)
-				goto reject;
+				sp = &dummy;
 
 			/* For each tmpl search corresponding xfrm.
 			 * Order is _important_. Later we will implement
@@ -1462,6 +1482,8 @@
 			 * are implied between each two transformations.
 			 */
 			for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) {
+				if (pol->xfrm_vec[i].optional)
+					continue;
 				switch (family) {
 				case AF_INET:
 					k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k);
diff -urN linux-2.5.65-bk1/net/ipv4/xfrm_state.c linux-2.5.65-bk2/net/ipv4/xfrm_state.c
--- linux-2.5.65-bk1/net/ipv4/xfrm_state.c	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/net/ipv4/xfrm_state.c	Mon Mar 31 12:39:51 2003
@@ -501,7 +501,7 @@
 
 int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
 {
-	int nhead = x->props.header_len + skb->dst->dev->hard_header_len
+	int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev)
 		- skb_headroom(skb);
 
 	if (nhead > 0)
diff -urN linux-2.5.65-bk1/net/ipv4/xfrm_user.c linux-2.5.65-bk2/net/ipv4/xfrm_user.c
--- linux-2.5.65-bk1/net/ipv4/xfrm_user.c	Mon Mar 17 13:44:08 2003
+++ linux-2.5.65-bk2/net/ipv4/xfrm_user.c	Mon Mar 31 12:39:51 2003
@@ -46,8 +46,14 @@
 	algp = RTA_DATA(rt);
 	switch (type) {
 	case XFRMA_ALG_AUTH:
+		if (!algp->alg_key_len &&
+		    strcmp(algp->alg_name, "digest_null") != 0)
+			return -EINVAL;
+		break;
+
 	case XFRMA_ALG_CRYPT:
-		if (!algp->alg_key_len)
+		if (!algp->alg_key_len &&
+		    strcmp(algp->alg_name, "cipher_null") != 0)
 			return -EINVAL;
 		break;
 
diff -urN linux-2.5.65-bk1/net/ipv6/Makefile linux-2.5.65-bk2/net/ipv6/Makefile
--- linux-2.5.65-bk1/net/ipv6/Makefile	Mon Mar 17 13:44:38 2003
+++ linux-2.5.65-bk2/net/ipv6/Makefile	Mon Mar 31 12:39:51 2003
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_IPV6) += ipv6.o
 
-ipv6-objs :=	af_inet6.o ip6_output.o ip6_input.o addrconf.o sit.o \
+ipv6-objs :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
 		route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
 		protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
diff -urN linux-2.5.65-bk1/net/ipv6/addrconf.c linux-2.5.65-bk2/net/ipv6/addrconf.c
--- linux-2.5.65-bk1/net/ipv6/addrconf.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/net/ipv6/addrconf.c	Mon Mar 31 12:39:51 2003
@@ -174,19 +174,13 @@
 
 int ipv6_addr_type(struct in6_addr *addr)
 {
+	int type;
 	u32 st;
 
 	st = addr->s6_addr32[0];
 
-	/* Consider all addresses with the first three bits different of
-	   000 and 111 as unicasts.
-	 */
-	if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
-	    (st & htonl(0xE0000000)) != htonl(0xE0000000))
-		return IPV6_ADDR_UNICAST;
-
 	if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
-		int type = IPV6_ADDR_MULTICAST;
+		type = IPV6_ADDR_MULTICAST;
 
 		switch((st & htonl(0x00FF0000))) {
 			case __constant_htonl(0x00010000):
@@ -203,29 +197,53 @@
 		};
 		return type;
 	}
+	/* check for reserved anycast addresses */
+	
+	if ((st & htonl(0xE0000000)) &&
+	    ((addr->s6_addr32[2] == htonl(0xFDFFFFFF) &&
+	    (addr->s6_addr32[3] | htonl(0x7F)) == (u32)~0) ||
+	    (addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0)))
+		type = IPV6_ADDR_ANYCAST;
+	else
+		type = IPV6_ADDR_UNICAST;
+
+	/* Consider all addresses with the first three bits different of
+	   000 and 111 as finished.
+	 */
+	if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
+	    (st & htonl(0xE0000000)) != htonl(0xE0000000))
+		return type;
 	
 	if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
-		return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST);
+		return (IPV6_ADDR_LINKLOCAL | type);
 
 	if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
-		return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST);
+		return (IPV6_ADDR_SITELOCAL | type);
 
 	if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
 		if (addr->s6_addr32[2] == 0) {
-			if (addr->s6_addr32[3] == 0)
+			if (addr->in6_u.u6_addr32[3] == 0)
 				return IPV6_ADDR_ANY;
 
 			if (addr->s6_addr32[3] == htonl(0x00000001))
-				return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST);
+				return (IPV6_ADDR_LOOPBACK | type);
 
-			return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST);
+			return (IPV6_ADDR_COMPATv4 | type);
 		}
 
 		if (addr->s6_addr32[2] == htonl(0x0000ffff))
 			return IPV6_ADDR_MAPPED;
 	}
 
-	return IPV6_ADDR_RESERVED;
+	st &= htonl(0xFF000000);
+	if (st == 0)
+		return IPV6_ADDR_RESERVED;
+	st &= htonl(0xFE000000);
+	if (st == htonl(0x02000000))
+		return IPV6_ADDR_RESERVED;	/* for NSAP */
+	if (st == htonl(0x04000000))
+		return IPV6_ADDR_RESERVED;	/* for IPX */
+	return type;
 }
 
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -261,7 +279,6 @@
 	add_timer(&ifp->timer);
 }
 
-
 /* Nobody refers to this device, we may destroy it. */
 
 void in6_dev_finish_destroy(struct inet6_dev *idev)
@@ -358,24 +375,91 @@
 	return idev;
 }
 
+void ipv6_addr_prefix(struct in6_addr *prefix,
+	struct in6_addr *addr, int prefix_len)
+{
+	unsigned long mask;
+	int ncopy, nbits;
+
+	memset(prefix, 0, sizeof(*prefix));
+
+	if (prefix_len <= 0)
+		return;
+	if (prefix_len > 128)
+		prefix_len = 128;
+
+	ncopy = prefix_len / 32;
+	switch (ncopy) {
+	case 4:	prefix->s6_addr32[3] = addr->s6_addr32[3];
+	case 3:	prefix->s6_addr32[2] = addr->s6_addr32[2];
+	case 2:	prefix->s6_addr32[1] = addr->s6_addr32[1];
+	case 1:	prefix->s6_addr32[0] = addr->s6_addr32[0];
+	case 0:	break;
+	}
+	nbits = prefix_len % 32;
+	if (nbits == 0)
+		return;
+
+	mask = ~((1 << (32 - nbits)) - 1);
+	mask = htonl(mask);
+
+	prefix->s6_addr32[ncopy] = addr->s6_addr32[ncopy] & mask;
+}
+
+
+static void dev_forward_change(struct inet6_dev *idev)
+{
+	struct net_device *dev;
+	struct inet6_ifaddr *ifa;
+	struct in6_addr addr;
+
+	if (!idev)
+		return;
+	dev = idev->dev;
+	if (dev && (dev->flags & IFF_MULTICAST)) {
+		ipv6_addr_all_routers(&addr);
+	
+		if (idev->cnf.forwarding)
+			ipv6_dev_mc_inc(dev, &addr);
+		else
+			ipv6_dev_mc_dec(dev, &addr);
+	}
+	for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+		ipv6_addr_prefix(&addr, &ifa->addr, ifa->prefix_len);
+		if (addr.s6_addr32[0] == 0 && addr.s6_addr32[1] == 0 &&
+		    addr.s6_addr32[2] == 0 && addr.s6_addr32[3] == 0)
+			continue;
+		if (idev->cnf.forwarding)
+			ipv6_dev_ac_inc(idev->dev, &addr);
+		else
+			ipv6_dev_ac_dec(idev->dev, &addr);
+	}
+}
+
+
 static void addrconf_forward_change(struct inet6_dev *idev)
 {
 	struct net_device *dev;
 
-	if (idev)
+	if (idev) {
+		dev_forward_change(idev);
 		return;
+	}
 
 	read_lock(&dev_base_lock);
 	for (dev=dev_base; dev; dev=dev->next) {
 		read_lock(&addrconf_lock);
 		idev = __in6_dev_get(dev);
-		if (idev)
+		if (idev) {
 			idev->cnf.forwarding = ipv6_devconf.forwarding;
+			dev_forward_change(idev);
+		}
 		read_unlock(&addrconf_lock);
 	}
 	read_unlock(&dev_base_lock);
 }
 
+
 /* Nobody refers to this ifaddr, destroy it */
 
 void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
@@ -658,30 +742,20 @@
 #define IPV6_GET_SADDR_MAXSCORE(score)	(score)
 #endif
 
-int ipv6_get_saddr(struct dst_entry *dst,
-		   struct in6_addr *daddr, struct in6_addr *saddr)
+int ipv6_dev_get_saddr(struct net_device *dev,
+		   struct in6_addr *daddr, struct in6_addr *saddr, int onlink)
 {
-	int scope;
 	struct inet6_ifaddr *ifp = NULL;
 	struct inet6_ifaddr *match = NULL;
-	struct net_device *dev = NULL;
 	struct inet6_dev *idev;
-	struct rt6_info *rt;
+	int scope;
 	int err;
 	int hiscore = -1, score;
 
-	rt = (struct rt6_info *) dst;
-	if (rt)
-		dev = rt->rt6i_dev;
-
-	scope = ipv6_addr_scope(daddr);
-	if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) {
-		/*
-		 *	route for the "all destinations on link" rule
-		 *	when no routers are present
-		 */
+	if (!onlink)
+		scope = ipv6_addr_scope(daddr);
+	else
 		scope = IFA_LINK;
-	}
 
 	/*
 	 *	known dev
@@ -782,6 +856,24 @@
 	return err;
 }
 
+
+int ipv6_get_saddr(struct dst_entry *dst,
+		   struct in6_addr *daddr, struct in6_addr *saddr)
+{
+	struct rt6_info *rt;
+	struct net_device *dev = NULL;
+	int onlink;
+
+	rt = (struct rt6_info *) dst;
+	if (rt)
+		dev = rt->rt6i_dev;
+
+	onlink = (rt && (rt->rt6i_flags & RTF_ALLONLINK));
+
+	return ipv6_dev_get_saddr(dev, daddr, saddr, onlink);
+}
+
+
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
 {
 	struct inet6_dev *idev;
@@ -889,7 +981,7 @@
 
 /* Join to solicited addr multicast group. */
 
-static void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
+void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
 {
 	struct in6_addr maddr;
 
@@ -900,7 +992,7 @@
 	ipv6_dev_mc_inc(dev, &maddr);
 }
 
-static void addrconf_leave_solict(struct net_device *dev, struct in6_addr *addr)
+void addrconf_leave_solict(struct net_device *dev, struct in6_addr *addr)
 {
 	struct in6_addr maddr;
 
@@ -1937,6 +2029,15 @@
 		addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval);
 		spin_unlock_bh(&ifp->lock);
 	}
+
+	if (ifp->idev->cnf.forwarding) {
+		struct in6_addr addr;
+
+		ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
+		if (addr.s6_addr32[0] || addr.s6_addr32[1] ||
+		    addr.s6_addr32[2] || addr.s6_addr32[3])
+			ipv6_dev_ac_inc(ifp->idev->dev, &addr);
+	}
 }
 
 #ifdef CONFIG_PROC_FS
@@ -2267,6 +2368,14 @@
 		break;
 	case RTM_DELADDR:
 		addrconf_leave_solict(ifp->idev->dev, &ifp->addr);
+		if (ifp->idev->cnf.forwarding) {
+			struct in6_addr addr;
+
+			ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
+			if (addr.s6_addr32[0] || addr.s6_addr32[1] ||
+			    addr.s6_addr32[2] || addr.s6_addr32[3])
+				ipv6_dev_ac_dec(ifp->idev->dev, &addr);
+		}
 		if (!ipv6_chk_addr(&ifp->addr, NULL))
 			ip6_rt_addr_del(&ifp->addr, ifp->idev->dev);
 		break;
@@ -2289,11 +2398,7 @@
 		struct inet6_dev *idev = NULL;
 
 		if (valp != &ipv6_devconf.forwarding) {
-			struct net_device *dev = dev_get_by_index(ctl->ctl_name);
-			if (dev) {
-				idev = in6_dev_get(dev);
-				dev_put(dev);
-			}
+			idev = (struct inet6_dev *)ctl->extra1;
 			if (idev == NULL)
 				return ret;
 		} else
@@ -2303,8 +2408,6 @@
 
 		if (*valp)
 			rt6_purge_dflt_routers(0);
-		if (idev)
-			in6_dev_put(idev);
 	}
 
         return ret;
@@ -2491,6 +2594,7 @@
 	for (i=0; t->addrconf_vars[i].data; i++) {
 		t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
 		t->addrconf_vars[i].de = NULL;
+		t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
 	}
 	if (dev) {
 		t->addrconf_dev[0].procname = dev->name;
diff -urN linux-2.5.65-bk1/net/ipv6/af_inet6.c linux-2.5.65-bk2/net/ipv6/af_inet6.c
--- linux-2.5.65-bk1/net/ipv6/af_inet6.c	Mon Mar 17 13:44:08 2003
+++ linux-2.5.65-bk2/net/ipv6/af_inet6.c	Mon Mar 31 12:39:51 2003
@@ -74,6 +74,7 @@
 /* IPv6 procfs goodies... */
 
 #ifdef CONFIG_PROC_FS
+extern int anycast6_get_info(char *, char **, off_t, int);
 extern int raw6_get_info(char *, char **, off_t, int);
 extern int tcp6_get_info(char *, char **, off_t, int);
 extern int udp6_get_info(char *, char **, off_t, int);
@@ -381,6 +382,9 @@
 	/* Free mc lists */
 	ipv6_sock_mc_close(sk);
 
+	/* Free ac lists */
+	ipv6_sock_ac_close(sk);
+
 	return inet_release(sock);
 }
 
@@ -785,6 +789,8 @@
 		goto proc_sockstat6_fail;
 	if (!proc_net_create("snmp6", 0, afinet6_get_snmp))
 		goto proc_snmp6_fail;
+	if (!proc_net_create("anycast6", 0, anycast6_get_info))
+		goto proc_anycast6_fail;
 #endif
 	ipv6_netdev_notif_init();
 	ipv6_packet_init();
@@ -800,6 +806,8 @@
 	return 0;
 
 #ifdef CONFIG_PROC_FS
+proc_anycast6_fail:
+	proc_net_remove("anycast6");
 proc_snmp6_fail:
 	proc_net_remove("sockstat6");
 proc_sockstat6_fail:
@@ -837,6 +845,7 @@
 	proc_net_remove("udp6");
 	proc_net_remove("sockstat6");
 	proc_net_remove("snmp6");
+	proc_net_remove("anycast6");
 #endif
 	/* Cleanup code parts. */
 	sit_cleanup();
diff -urN linux-2.5.65-bk1/net/ipv6/ah6.c linux-2.5.65-bk2/net/ipv6/ah6.c
--- linux-2.5.65-bk1/net/ipv6/ah6.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/net/ipv6/ah6.c	Mon Mar 31 12:39:51 2003
@@ -60,9 +60,11 @@
 	struct ah_data *ahp;
 	u16 nh_offset = 0;
 	u8 nexthdr;
-printk(KERN_DEBUG "%s\n", __FUNCTION__);
-	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL)
-		return -EINVAL;
+
+	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
+		err = -EINVAL;
+		goto error_nolock;
+	}
 
 	spin_lock_bh(&x->lock);
 	if ((err = xfrm_state_check_expire(x)) != 0)
@@ -134,8 +136,10 @@
 	x->curlft.bytes += skb->len;
 	x->curlft.packets++;
 	spin_unlock_bh(&x->lock);
-	if ((skb->dst = dst_pop(dst)) == NULL)
+	if ((skb->dst = dst_pop(dst)) == NULL) {
+		err = -EHOSTUNREACH;
 		goto error_nolock;
+	}
 	return NET_XMIT_BYPASS;
 error:
 	spin_unlock_bh(&x->lock);
diff -urN linux-2.5.65-bk1/net/ipv6/anycast.c linux-2.5.65-bk2/net/ipv6/anycast.c
--- linux-2.5.65-bk1/net/ipv6/anycast.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/net/ipv6/anycast.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,489 @@
+/*
+ *	Anycast support for IPv6
+ *	Linux INET6 implementation 
+ *
+ *	Authors:
+ *	David L Stevens (dlstevens@us.ibm.com)
+ *
+ *	based heavily on net/ipv6/mcast.c
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/route.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/if_inet6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+
+#include <net/checksum.h>
+
+/* Big ac list lock for all the sockets */
+static rwlock_t ipv6_sk_ac_lock = RW_LOCK_UNLOCKED;
+
+/* XXX ip6_addr_match() and ip6_onlink() really belong in net/core.c */
+
+static int
+ip6_addr_match(struct in6_addr *addr1, struct in6_addr *addr2, int prefix)
+{
+	__u32	mask;
+	int	i;
+
+	if (prefix > 128 || prefix < 0)
+		return 0;
+	if (prefix == 0)
+		return 1;
+	for (i=0; i<4; ++i) {
+		if (prefix >= 32)
+			mask = ~0;
+		else
+			mask = htonl(~0 << (32 - prefix));
+		if ((addr1->s6_addr32[i] ^ addr2->s6_addr32[i]) & mask)
+			return 0;
+		prefix -= 32;
+		if (prefix <= 0)
+			break;
+	}
+	return 1;
+}
+
+static int
+ip6_onlink(struct in6_addr *addr, struct net_device *dev)
+{
+	struct inet6_dev	*idev;
+	struct inet6_ifaddr	*ifa;
+	int	onlink;
+
+	onlink = 0;
+	read_lock(&addrconf_lock);
+	idev = __in6_dev_get(dev);
+	if (idev) {
+		read_lock_bh(&idev->lock);
+		for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+			onlink = ip6_addr_match(addr, &ifa->addr,
+					ifa->prefix_len);
+			if (onlink)
+				break;
+		}
+		read_unlock_bh(&idev->lock);
+	}
+	read_unlock(&addrconf_lock);
+	return onlink;
+}
+
+
+/*
+ *	socket join an anycast group
+ */
+
+int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
+{
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct net_device *dev = NULL;
+	struct inet6_dev *idev;
+	struct ipv6_ac_socklist *pac;
+	int	ishost = !ipv6_devconf.forwarding;
+	int	err = 0;
+
+	if (ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST)
+		return -EINVAL;
+
+	pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL);
+	if (pac == NULL)
+		return -ENOMEM;
+	pac->acl_next = NULL;
+	ipv6_addr_copy(&pac->acl_addr, addr);
+
+	if (ifindex == 0) {
+		struct rt6_info *rt;
+
+		rt = rt6_lookup(addr, NULL, 0, 0);
+		if (rt) {
+			dev = rt->rt6i_dev;
+			dev_hold(dev);
+			dst_release(&rt->u.dst);
+		} else if (ishost) {
+			sock_kfree_s(sk, pac, sizeof(*pac));
+			return -EADDRNOTAVAIL;
+		} else {
+			/* router, no matching interface: just pick one */
+
+			dev = dev_get_by_flags(IFF_UP, IFF_UP|IFF_LOOPBACK);
+		}
+	} else
+		dev = dev_get_by_index(ifindex);
+
+	if (dev == NULL) {
+		sock_kfree_s(sk, pac, sizeof(*pac));
+		return -ENODEV;
+	}
+
+	idev = in6_dev_get(dev);
+	if (!idev) {
+		sock_kfree_s(sk, pac, sizeof(*pac));
+		dev_put(dev);
+		if (ifindex)
+			return -ENODEV;
+		else
+			return -EADDRNOTAVAIL;
+	}
+	/* reset ishost, now that we have a specific device */
+	ishost = !idev->cnf.forwarding;
+	in6_dev_put(idev);
+
+	pac->acl_ifindex = dev->ifindex;
+
+	/* XXX
+	 * For hosts, allow link-local or matching prefix anycasts.
+	 * This obviates the need for propagating anycast routes while
+	 * still allowing some non-router anycast participation.
+	 *
+	 * allow anyone to join anycasts that don't require a special route
+	 * and can't be spoofs of unicast addresses (reserved anycast only)
+	 */
+	if (!ip6_onlink(addr, dev)) {
+		if (ishost)
+			err = -EADDRNOTAVAIL;
+		else if (!capable(CAP_NET_ADMIN))
+			err = -EPERM;
+		if (err) {
+			sock_kfree_s(sk, pac, sizeof(*pac));
+			dev_put(dev);
+			return err;
+		}
+	} else if (!(ipv6_addr_type(addr) & IPV6_ADDR_ANYCAST) &&
+		   !capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	err = ipv6_dev_ac_inc(dev, addr);
+	if (err) {
+		sock_kfree_s(sk, pac, sizeof(*pac));
+		dev_put(dev);
+		return err;
+	}
+
+	write_lock_bh(&ipv6_sk_ac_lock);
+	pac->acl_next = np->ipv6_ac_list;
+	np->ipv6_ac_list = pac;
+	write_unlock_bh(&ipv6_sk_ac_lock);
+
+	dev_put(dev);
+
+	return 0;
+}
+
+/*
+ *	socket leave an anycast group
+ */
+int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
+{
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct net_device *dev;
+	struct ipv6_ac_socklist *pac, *prev_pac;
+
+	write_lock_bh(&ipv6_sk_ac_lock);
+	prev_pac = 0;
+	for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) {
+		if ((ifindex == 0 || pac->acl_ifindex == ifindex) &&
+		     ipv6_addr_cmp(&pac->acl_addr, addr) == 0)
+			break;
+		prev_pac = pac;
+	}
+	if (!pac) {
+		write_unlock_bh(&ipv6_sk_ac_lock);
+		return -ENOENT;
+	}
+	if (prev_pac)
+		prev_pac->acl_next = pac->acl_next;
+	else
+		np->ipv6_ac_list = pac->acl_next;
+
+	write_unlock_bh(&ipv6_sk_ac_lock);
+
+	dev = dev_get_by_index(pac->acl_ifindex);
+	if (dev) {
+		ipv6_dev_ac_dec(dev, &pac->acl_addr);
+		dev_put(dev);
+	}
+	sock_kfree_s(sk, pac, sizeof(*pac));
+	return 0;
+}
+
+void ipv6_sock_ac_close(struct sock *sk)
+{
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct net_device *dev = 0;
+	struct ipv6_ac_socklist *pac;
+	int	prev_index;
+
+	write_lock_bh(&ipv6_sk_ac_lock);
+	pac = np->ipv6_ac_list;
+	np->ipv6_ac_list = 0;
+	write_unlock_bh(&ipv6_sk_ac_lock);
+
+	prev_index = 0;
+	while (pac) {
+		struct ipv6_ac_socklist *next = pac->acl_next;
+
+		if (pac->acl_ifindex != prev_index) {
+			if (dev)
+				dev_put(dev);
+			dev = dev_get_by_index(pac->acl_ifindex);
+			prev_index = pac->acl_ifindex;
+		}
+		if (dev)
+			ipv6_dev_ac_dec(dev, &pac->acl_addr);
+		sock_kfree_s(sk, pac, sizeof(*pac));
+		pac = next;
+	}
+	if (dev)
+		dev_put(dev);
+}
+
+int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex)
+{
+	struct ipv6_ac_socklist *pac;
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	int	found;
+
+	found = 0;
+	read_lock(&ipv6_sk_ac_lock);
+	for (pac=np->ipv6_ac_list; pac; pac=pac->acl_next) {
+		if (ifindex && pac->acl_ifindex != ifindex)
+			continue;
+		found = ipv6_addr_cmp(&pac->acl_addr, addr) == 0;
+		if (found)
+			break;
+	}
+	read_unlock(&ipv6_sk_ac_lock);
+
+	return found;
+}
+
+static void aca_put(struct ifacaddr6 *ac)
+{
+	if (atomic_dec_and_test(&ac->aca_refcnt)) {
+		in6_dev_put(ac->aca_idev);
+		kfree(ac);
+	}
+}
+
+/*
+ *	device anycast group inc (add if not found)
+ */
+int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
+{
+	struct ifacaddr6 *aca;
+	struct inet6_dev *idev;
+
+	idev = in6_dev_get(dev);
+
+	if (idev == NULL)
+		return -EINVAL;
+
+	write_lock_bh(&idev->lock);
+	if (idev->dead) {
+		write_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return -ENODEV;
+	}
+
+	for (aca = idev->ac_list; aca; aca = aca->aca_next) {
+		if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0) {
+			aca->aca_users++;
+			write_unlock_bh(&idev->lock);
+			in6_dev_put(idev);
+			return 0;
+		}
+	}
+
+	/*
+	 *	not found: create a new one.
+	 */
+
+	aca = kmalloc(sizeof(struct ifacaddr6), GFP_ATOMIC);
+
+	if (aca == NULL) {
+		write_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return -ENOMEM;
+	}
+
+	memset(aca, 0, sizeof(struct ifacaddr6));
+
+	ipv6_addr_copy(&aca->aca_addr, addr);
+	aca->aca_idev = idev;
+	aca->aca_users = 1;
+	atomic_set(&aca->aca_refcnt, 2);
+	aca->aca_lock = SPIN_LOCK_UNLOCKED;
+
+	aca->aca_next = idev->ac_list;
+	idev->ac_list = aca;
+	write_unlock_bh(&idev->lock);
+
+	ip6_rt_addr_add(&aca->aca_addr, dev);
+
+	addrconf_join_solict(dev, &aca->aca_addr);
+
+	aca_put(aca);
+	return 0;
+}
+
+/*
+ *	device anycast group decrement
+ */
+int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
+{
+	struct inet6_dev *idev;
+	struct ifacaddr6 *aca, *prev_aca;
+
+	idev = in6_dev_get(dev);
+	if (idev == NULL)
+		return -ENODEV;
+
+	write_lock_bh(&idev->lock);
+	prev_aca = 0;
+	for (aca = idev->ac_list; aca; aca = aca->aca_next) {
+		if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0)
+			break;
+		prev_aca = aca;
+	}
+	if (!aca) {
+		write_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return -ENOENT;
+	}
+	if (--aca->aca_users > 0) {
+		write_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return 0;
+	}
+	if (prev_aca)
+		prev_aca->aca_next = aca->aca_next;
+	else
+		idev->ac_list = aca->aca_next;
+	write_unlock_bh(&idev->lock);
+	addrconf_leave_solict(dev, &aca->aca_addr);
+
+	ip6_rt_addr_del(&aca->aca_addr, dev);
+
+	aca_put(aca);
+	in6_dev_put(idev);
+	return 0;
+}
+
+/*
+ *	check if the interface has this anycast address
+ */
+static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
+{
+	struct inet6_dev *idev;
+	struct ifacaddr6 *aca;
+
+	idev = in6_dev_get(dev);
+	if (idev) {
+		read_lock_bh(&idev->lock);
+		for (aca = idev->ac_list; aca; aca = aca->aca_next)
+			if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0)
+				break;
+		read_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return aca != 0;
+	}
+	return 0;
+}
+
+/*
+ *	check if given interface (or any, if dev==0) has this anycast address
+ */
+int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr)
+{
+	if (dev)
+		return ipv6_chk_acast_dev(dev, addr);
+	read_lock(&dev_base_lock);
+	for (dev=dev_base; dev; dev=dev->next)
+		if (ipv6_chk_acast_dev(dev, addr))
+			break;
+	read_unlock(&dev_base_lock);
+	return dev != 0;
+}
+
+
+#ifdef CONFIG_PROC_FS
+int anycast6_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	off_t pos=0, begin=0;
+	struct ifacaddr6 *im;
+	int len=0;
+	struct net_device *dev;
+	
+	read_lock(&dev_base_lock);
+	for (dev = dev_base; dev; dev = dev->next) {
+		struct inet6_dev *idev;
+
+		if ((idev = in6_dev_get(dev)) == NULL)
+			continue;
+
+		read_lock_bh(&idev->lock);
+		for (im = idev->ac_list; im; im = im->aca_next) {
+			int i;
+
+			len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
+
+			for (i=0; i<16; i++)
+				len += sprintf(buffer+len, "%02x", im->aca_addr.s6_addr[i]);
+
+			len += sprintf(buffer+len, " %5d\n", im->aca_users);
+
+			pos=begin+len;
+			if (pos < offset) {
+				len=0;
+				begin=pos;
+			}
+			if (pos > offset+length) {
+				read_unlock_bh(&idev->lock);
+				in6_dev_put(idev);
+				goto done;
+			}
+		}
+		read_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+	}
+
+done:
+	read_unlock(&dev_base_lock);
+
+	*start=buffer+(offset-begin);
+	len-=(offset-begin);
+	if(len>length)
+		len=length;
+	if (len<0)
+		len=0;
+	return len;
+}
+
+#endif
diff -urN linux-2.5.65-bk1/net/ipv6/esp6.c linux-2.5.65-bk2/net/ipv6/esp6.c
--- linux-2.5.65-bk1/net/ipv6/esp6.c	Mon Mar 17 13:44:15 2003
+++ linux-2.5.65-bk2/net/ipv6/esp6.c	Mon Mar 31 12:39:51 2003
@@ -118,10 +118,12 @@
 	int alen;
 	int nfrags;
 	u8 nexthdr;
-printk(KERN_DEBUG "%s\n", __FUNCTION__);
+
 	/* First, if the skb is not checksummed, complete checksum. */
-	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL)
-		return -EINVAL;
+	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
+		err = -EINVAL;
+		goto error_nolock;
+	}
 
 	spin_lock_bh(&x->lock);
 	if ((err = xfrm_state_check_expire(x)) != 0)
@@ -239,8 +241,10 @@
 	x->curlft.bytes += skb->len;
 	x->curlft.packets++;
 	spin_unlock_bh(&x->lock);
-	if ((skb->dst = dst_pop(dst)) == NULL)
+	if ((skb->dst = dst_pop(dst)) == NULL) {
+		err = -EHOSTUNREACH;
 		goto error_nolock;
+	}
 	return NET_XMIT_BYPASS;
 
 error:
diff -urN linux-2.5.65-bk1/net/ipv6/icmp.c linux-2.5.65-bk2/net/ipv6/icmp.c
--- linux-2.5.65-bk1/net/ipv6/icmp.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/net/ipv6/icmp.c	Mon Mar 31 12:39:51 2003
@@ -369,7 +369,8 @@
 
 	saddr = &skb->nh.ipv6h->daddr;
 
-	if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST)
+	if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST ||
+	    ipv6_chk_acast_addr(0, saddr)) 
 		saddr = NULL;
 
 	msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY;
diff -urN linux-2.5.65-bk1/net/ipv6/ipv6_sockglue.c linux-2.5.65-bk2/net/ipv6/ipv6_sockglue.c
--- linux-2.5.65-bk1/net/ipv6/ipv6_sockglue.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/net/ipv6/ipv6_sockglue.c	Mon Mar 31 12:39:51 2003
@@ -358,6 +358,24 @@
 			retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
 		break;
 	}
+	case IPV6_JOIN_ANYCAST:
+	case IPV6_LEAVE_ANYCAST:
+	{
+		struct ipv6_mreq mreq;
+
+		if (optlen != sizeof(struct ipv6_mreq))
+			goto e_inval;
+
+		retv = -EFAULT;
+		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
+			break;
+
+		if (optname == IPV6_JOIN_ANYCAST)
+			retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
+		else
+			retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
+		break;
+	}
 	case IPV6_ROUTER_ALERT:
 		retv = ip6_ra_control(sk, val, NULL);
 		break;
diff -urN linux-2.5.65-bk1/net/ipv6/ndisc.c linux-2.5.65-bk2/net/ipv6/ndisc.c
--- linux-2.5.65-bk1/net/ipv6/ndisc.c	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/net/ipv6/ndisc.c	Mon Mar 31 12:39:51 2003
@@ -413,10 +413,13 @@
 		   struct in6_addr *daddr, struct in6_addr *solicited_addr,
 	 	   int router, int solicited, int override, int inc_opt) 
 {
+	static struct in6_addr tmpaddr;
+	struct inet6_ifaddr *ifp;
 	struct flowi fl;
 	struct rt6_info *rt = NULL;
 	struct dst_entry* dst;
         struct sock *sk = ndisc_socket->sk;
+	struct in6_addr *src_addr;
         struct nd_msg *msg;
         int len;
         struct sk_buff *skb;
@@ -428,7 +431,18 @@
 	if (!rt) 
 		return;
 
-	ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, solicited_addr, daddr);
+	/* for anycast or proxy, solicited_addr != src_addr */
+	ifp = ipv6_get_ifaddr(solicited_addr, dev);
+ 	if (ifp) {
+		src_addr = solicited_addr;
+		in6_ifa_put(ifp);
+	} else {
+		if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, 0))
+			return;
+		src_addr = &tmpaddr;
+	}
+
+	ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr);
 	ndisc_rt_init(rt, dev, neigh);	
 
 	dst = (struct dst_entry*)rt;
@@ -456,7 +470,7 @@
 	}
 
 	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
-	ip6_nd_hdr(sk, skb, dev, solicited_addr, daddr, IPPROTO_ICMPV6, len);
+	ip6_nd_hdr(sk, skb, dev, src_addr, daddr, IPPROTO_ICMPV6, len);
 
 	skb->h.raw = (unsigned char*) msg = (struct nd_msg *) skb_put(skb, len);
 
@@ -470,13 +484,13 @@
         msg->icmph.icmp6_override  = !!override;
 
         /* Set the target address. */
-	ipv6_addr_copy(&msg->target, solicited_addr);
+	ipv6_addr_copy(&msg->target, src_addr);
 
 	if (inc_opt)
 		ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
 
 	/* checksum */
-	msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len, 
+	msg->icmph.icmp6_cksum = csum_ipv6_magic(src_addr, daddr, len, 
 						 IPPROTO_ICMPV6,
 						 csum_partial((__u8 *) msg, 
 							      len, 0));
@@ -793,6 +807,50 @@
 			}
 		}
 		in6_ifa_put(ifp);
+	} else if (ipv6_chk_acast_addr(dev, &msg->target)) {
+		struct inet6_dev *idev = in6_dev_get(dev);
+		int addr_type = ipv6_addr_type(saddr);
+	
+		/* anycast */
+	
+		if (!idev) {
+			/* XXX: count this drop? */
+			return;
+		}
+	
+		if (addr_type == IPV6_ADDR_ANY) {
+			struct in6_addr maddr;
+	
+			ipv6_addr_all_nodes(&maddr);
+			ndisc_send_na(dev, NULL, &maddr, &msg->target,
+				      idev->cnf.forwarding, 0, 0, 1);
+			in6_dev_put(idev);
+			return;
+		}
+
+		if (addr_type & IPV6_ADDR_UNICAST) {
+			int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
+			if (inc)  
+				nd_tbl.stats.rcv_probes_mcast++;
+			else
+				nd_tbl.stats.rcv_probes_ucast++;
+	
+			/*
+			 *   update / create cache entry
+			 *   for the source adddress
+			 */
+
+			neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
+
+			if (neigh || !dev->hard_header) {
+				ndisc_send_na(dev, neigh, saddr,
+					      &msg->target, 
+					      idev->cnf.forwarding, 1, 0, inc);
+				if (neigh)
+					neigh_release(neigh);
+			}
+		}
+		in6_dev_put(idev);
 	} else {
 		struct inet6_dev *in6_dev = in6_dev_get(dev);
 		int addr_type = ipv6_addr_type(saddr);
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6_queue.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6_queue.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6_queue.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6_queue.c	Mon Mar 31 12:39:51 2003
@@ -558,9 +558,7 @@
 }
 
 static struct notifier_block ipq_dev_notifier = {
-	ipq_rcv_dev_event,
-	NULL,
-	0
+	.notifier_call	= ipq_rcv_dev_event,
 };
 
 static int
@@ -580,9 +578,7 @@
 }
 
 static struct notifier_block ipq_nl_notifier = {
-	ipq_rcv_nl_event,
-	NULL,
-	0
+	.notifier_call	= ipq_rcv_nl_event,
 };
 
 static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
@@ -604,7 +600,6 @@
 	{
 		.ctl_name	= NET_IPV6,
 		.procname	= "ipv6",
-		.maxlen		= 0,
 		.mode		= 0555,
 		.child		= ipq_table
 	},
@@ -615,7 +610,6 @@
 	{
 		.ctl_name	= CTL_NET,
 		.procname	= "net",
-		.maxlen		= 0,
 		.mode		= 0555,
 		.child		= ipq_dir_table
 	},
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6_tables.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6_tables.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6_tables.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6_tables.c	Mon Mar 31 12:39:51 2003
@@ -1735,21 +1735,42 @@
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct ip6t_target ip6t_standard_target
-= { { NULL, NULL }, IP6T_STANDARD_TARGET, NULL, NULL, NULL };
-static struct ip6t_target ip6t_error_target
-= { { NULL, NULL }, IP6T_ERROR_TARGET, ip6t_error, NULL, NULL };
-
-static struct nf_sockopt_ops ip6t_sockopts
-= { { NULL, NULL }, PF_INET6, IP6T_BASE_CTL, IP6T_SO_SET_MAX+1, do_ip6t_set_ctl,
-    IP6T_BASE_CTL, IP6T_SO_GET_MAX+1, do_ip6t_get_ctl, 0, NULL  };
-
-static struct ip6t_match tcp_matchstruct
-= { { NULL, NULL }, "tcp", &tcp_match, &tcp_checkentry, NULL };
-static struct ip6t_match udp_matchstruct
-= { { NULL, NULL }, "udp", &udp_match, &udp_checkentry, NULL };
-static struct ip6t_match icmp6_matchstruct
-= { { NULL, NULL }, "icmp6", &icmp6_match, &icmp6_checkentry, NULL };
+static struct ip6t_target ip6t_standard_target = {
+	.name		= IP6T_STANDARD_TARGET,
+};
+
+static struct ip6t_target ip6t_error_target = {
+	.name		= IP6T_ERROR_TARGET,
+	.target		= ip6t_error,
+};
+
+static struct nf_sockopt_ops ip6t_sockopts = {
+	.pf		= PF_INET6,
+	.set_optmin	= IP6T_BASE_CTL,
+	.set_optmax	= IP6T_SO_SET_MAX+1,
+	.set		= do_ip6t_set_ctl,
+	.get_optmin	= IP6T_BASE_CTL,
+	.get_optmax	= IP6T_SO_GET_MAX+1,
+	.get		= do_ip6t_get_ctl,
+};
+
+static struct ip6t_match tcp_matchstruct = {
+	.name		= "tcp",
+	.match		= &tcp_match,
+	.checkentry	= &tcp_checkentry,
+};
+
+static struct ip6t_match udp_matchstruct = {
+	.name		= "udp",
+	.match		= &udp_match,
+	.checkentry	= &udp_checkentry,
+};
+
+static struct ip6t_match icmp6_matchstruct = {
+	.name		= "icmp6",
+	.match		= &icmp6_match,
+	.checkentry	= &icmp6_checkentry,
+};
 
 #ifdef CONFIG_PROC_FS
 static inline int print_name(const struct ip6t_table *t,
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_ah.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_ah.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_ah.c	Mon Mar 17 13:43:42 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_ah.c	Mon Mar 31 12:39:51 2003
@@ -26,17 +26,6 @@
        __u32   spi;
 };
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
@@ -79,7 +68,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_ah header iteration \n");
@@ -200,8 +189,12 @@
        return 1;
 }
 
-static struct ip6t_match ah_match
-= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+static struct ip6t_match ah_match = {
+	.name		= "ah",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_dst.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_dst.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_dst.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_dst.c	Mon Mar 31 12:39:51 2003
@@ -29,17 +29,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /*
  * (Type & 0xC0) >> 6
  * 	0	-> ignorable
@@ -84,7 +73,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_opts header iteration \n");
@@ -265,12 +254,15 @@
        return 1;
 }
 
-static struct ip6t_match opts_match
+static struct ip6t_match opts_match = {
 #if HOPBYHOP
-= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE };
+	.name		= "hbh",
 #else
-= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE };
+	.name		= "dst",
 #endif
+	.match		= &match,
+	.checkentry	= &checkentry,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_esp.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_esp.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_esp.c	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_esp.c	Mon Mar 31 12:39:51 2003
@@ -23,17 +23,6 @@
 	__u32   spi;
 };
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
@@ -74,7 +63,7 @@
 	len = skb->len - ptr;
 	temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
         	struct ipv6_opt_hdr *hdr;
         	int hdrlen;
 
@@ -168,8 +157,12 @@
 	return 1;
 }
 
-static struct ip6t_match esp_match
-= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+static struct ip6t_match esp_match = {
+	.name		= "esp",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_eui64.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_eui64.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_eui64.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_eui64.c	Mon Mar 31 12:39:51 2003
@@ -69,8 +69,12 @@
 	return 1;
 }
 
-static struct ip6t_match eui64_match
-= { { NULL, NULL }, "eui64", &match, &ip6t_eui64_checkentry, NULL, THIS_MODULE };
+static struct ip6t_match eui64_match = {
+	.name		= "eui64",
+	.match		= &match,
+	.checkentry	= &ip6t_eui64_checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_frag.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_frag.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_frag.c	Mon Mar 17 13:43:47 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_frag.c	Mon Mar 31 12:39:51 2003
@@ -44,17 +44,6 @@
        __u32   id;
 };
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /* Returns 1 if the id is matched by the range, 0 otherwise */
 static inline int
 id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
@@ -93,7 +82,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_frag header iteration \n");
@@ -232,8 +221,12 @@
        return 1;
 }
 
-static struct ip6t_match frag_match
-= { { NULL, NULL }, "frag", &match, &checkentry, NULL, THIS_MODULE };
+static struct ip6t_match frag_match = {
+	.name		= "frag",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_hbh.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_hbh.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_hbh.c	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_hbh.c	Mon Mar 31 12:39:51 2003
@@ -29,17 +29,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /*
  * (Type & 0xC0) >> 6
  * 	0	-> ignorable
@@ -84,7 +73,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_opts header iteration \n");
@@ -265,12 +254,16 @@
        return 1;
 }
 
-static struct ip6t_match opts_match
+static struct ip6t_match opts_match = {
 #if HOPBYHOP
-= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE };
+	.name		= "hbh",
 #else
-= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE };
+	.name		= "dst",
 #endif
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_hl.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_hl.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_hl.c	Mon Mar 17 13:44:19 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_hl.c	Mon Mar 31 12:39:51 2003
@@ -56,8 +56,12 @@
 	return 1;
 }
 
-static struct ip6t_match hl_match = { { NULL, NULL }, "hl", &match,
-		&checkentry, NULL, THIS_MODULE };
+static struct ip6t_match hl_match = {
+	.name		= "hl",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_ipv6header.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_ipv6header.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_ipv6header.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_ipv6header.c	Mon Mar 31 12:39:51 2003
@@ -24,17 +24,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 static int
 ipv6header_match(const struct sk_buff *skb,
 		 const struct net_device *in,
@@ -95,7 +84,7 @@
 
 	temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
         	struct ipv6_opt_hdr *hdr;
         	int hdrlen;
 
@@ -196,14 +185,12 @@
 	return;
 }
 
-static struct ip6t_match
-ip6t_ipv6header_match = {
-	{ NULL, NULL },
-	"ipv6header",
-	&ipv6header_match,
-	&ipv6header_checkentry,
-	&ipv6header_destroy,
-	THIS_MODULE
+static struct ip6t_match ip6t_ipv6header_match = {
+	.name		= "ipv6header",
+	.match		= &ipv6header_match,
+	.checkentry	= &ipv6header_checkentry,
+	.destroy	= &ipv6header_destroy,
+	.me		= THIS_MODULE,
 };
 
 static int  __init ipv6header_init(void)
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_length.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_length.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_length.c	Mon Mar 17 13:44:49 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_length.c	Mon Mar 31 12:39:51 2003
@@ -34,8 +34,12 @@
 	return 1;
 }
 
-static struct ip6t_match length_match
-= { { NULL, NULL }, "length", &match, &checkentry, NULL, THIS_MODULE };
+static struct ip6t_match length_match = {
+	.name		= "length",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_limit.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_limit.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_limit.c	Mon Mar 17 13:43:49 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_limit.c	Mon Mar 31 12:39:51 2003
@@ -115,9 +115,12 @@
 	return 1;
 }
 
-static struct ip6t_match ip6t_limit_reg
-= { { NULL, NULL }, "limit", ip6t_limit_match, ip6t_limit_checkentry, NULL,
-    THIS_MODULE };
+static struct ip6t_match ip6t_limit_reg = {
+	.name		= "limit",
+	.match		= ip6t_limit_match,
+	.checkentry	= ip6t_limit_checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_mac.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_mac.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_mac.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_mac.c	Mon Mar 31 12:39:51 2003
@@ -47,8 +47,12 @@
 	return 1;
 }
 
-static struct ip6t_match mac_match
-= { { NULL, NULL }, "mac", &match, &ip6t_mac_checkentry, NULL, THIS_MODULE };
+static struct ip6t_match mac_match = {
+	.name		= "mac",
+	.match		= &match,
+	.checkentry	= &ip6t_mac_checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_mark.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_mark.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_mark.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_mark.c	Mon Mar 31 12:39:51 2003
@@ -33,8 +33,12 @@
 	return 1;
 }
 
-static struct ip6t_match mark_match
-= { { NULL, NULL }, "mark", &match, &checkentry, NULL, THIS_MODULE };
+static struct ip6t_match mark_match = {
+	.name		= "mark",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_multiport.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_multiport.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_multiport.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_multiport.c	Mon Mar 31 12:39:51 2003
@@ -84,8 +84,12 @@
 		&& multiinfo->count <= IP6T_MULTI_PORTS;
 }
 
-static struct ip6t_match multiport_match
-= { { NULL, NULL }, "multiport", &match, &checkentry, NULL, THIS_MODULE };
+static struct ip6t_match multiport_match = {
+	.name		= "multiport",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_owner.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_owner.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_owner.c	Mon Mar 17 13:44:39 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_owner.c	Mon Mar 31 12:39:51 2003
@@ -142,8 +142,12 @@
 	return 1;
 }
 
-static struct ip6t_match owner_match
-= { { NULL, NULL }, "owner", &match, &checkentry, NULL, THIS_MODULE };
+static struct ip6t_match owner_match = {
+	.name		= "owner",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_rt.c linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_rt.c
--- linux-2.5.65-bk1/net/ipv6/netfilter/ip6t_rt.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/net/ipv6/netfilter/ip6t_rt.c	Mon Mar 31 12:39:51 2003
@@ -21,17 +21,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /* Returns 1 if the id is matched by the range, 0 otherwise */
 static inline int
 segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
@@ -71,7 +60,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_rt header iteration \n");
@@ -287,8 +276,12 @@
        return 1;
 }
 
-static struct ip6t_match rt_match
-= { { NULL, NULL }, "rt", &match, &checkentry, NULL, THIS_MODULE };
+static struct ip6t_match rt_match = {
+	.name		= "rt",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
 
 static int __init init(void)
 {
diff -urN linux-2.5.65-bk1/net/ipv6/sit.c linux-2.5.65-bk2/net/ipv6/sit.c
--- linux-2.5.65-bk1/net/ipv6/sit.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/net/ipv6/sit.c	Mon Mar 31 12:39:51 2003
@@ -181,7 +181,6 @@
 	nt = (struct ip_tunnel*)dev->priv;
 	nt->dev = dev;
 	dev->init = ipip6_tunnel_init;
-	dev->features |= NETIF_F_DYNALLOC;
 	memcpy(&nt->parms, parms, sizeof(*parms));
 	nt->parms.name[IFNAMSIZ-1] = '\0';
 	strcpy(dev->name, nt->parms.name);
@@ -213,6 +212,7 @@
 static void ipip6_tunnel_destructor(struct net_device *dev)
 {
 	if (dev != &ipip6_fb_tunnel_dev) {
+		kfree(dev);
 		MOD_DEC_USE_COUNT;
 	}
 }
@@ -552,7 +552,7 @@
 	/*
 	 * Okay, now see if we can stuff it in the buffer as-is.
 	 */
-	max_headroom = (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr));
+	max_headroom = LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr);
 
 	if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
 		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
diff -urN linux-2.5.65-bk1/net/irda/irda_device.c linux-2.5.65-bk2/net/irda/irda_device.c
--- linux-2.5.65-bk1/net/irda/irda_device.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/net/irda/irda_device.c	Mon Mar 31 12:39:51 2003
@@ -372,6 +372,11 @@
 	irda_task_kick(task);
 }
 
+static void irda_device_destructor(struct net_device *dev)
+{
+	kfree(dev);
+}
+
 /*
  * Function irda_device_setup (dev)
  *
@@ -385,8 +390,7 @@
         dev->hard_header_len = 0;
         dev->addr_len        = 0;
 
-	dev->features        |= NETIF_F_DYNALLOC;
-	/* dev->destructor      = irda_device_destructor; */
+	dev->destructor      = irda_device_destructor;
 
         dev->type            = ARPHRD_IRDA;
         dev->tx_queue_len    = 8; /* Window size + 1 s-frame */
diff -urN linux-2.5.65-bk1/net/irda/irlan/irlan_eth.c linux-2.5.65-bk2/net/irda/irlan/irlan_eth.c
--- linux-2.5.65-bk1/net/irda/irlan/irlan_eth.c	Mon Mar 17 13:43:49 2003
+++ linux-2.5.65-bk2/net/irda/irlan/irlan_eth.c	Mon Mar 31 12:39:51 2003
@@ -62,16 +62,6 @@
 	dev->get_stats	        = irlan_eth_get_stats;
 	dev->set_multicast_list = irlan_eth_set_multicast_list;
 
-	/* NETIF_F_DYNALLOC feature was set by irlan_eth_init() and would
-	 * cause the unregister_netdev() to do asynch completion _and_
-	 * kfree self->dev afterwards. Which is really bad because the
-	 * netdevice was not allocated separately but is embedded in
-	 * our control block and therefore gets freed with *self.
-	 * The only reason why this would have been enabled is to hide
-	 * some netdev refcount issues. If unregister_netdev() blocks
-	 * forever, tell us about it... */
-	//dev->features          |= NETIF_F_DYNALLOC;
-
 	ether_setup(dev);
 	
 	/* 
diff -urN linux-2.5.65-bk1/net/key/af_key.c linux-2.5.65-bk2/net/key/af_key.c
--- linux-2.5.65-bk1/net/key/af_key.c	Mon Mar 17 13:43:49 2003
+++ linux-2.5.65-bk2/net/key/af_key.c	Mon Mar 31 12:39:51 2003
@@ -900,6 +900,7 @@
 		return ERR_PTR(-EINVAL);
 	key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1];
 	if (key != NULL &&
+	    sa->sadb_sa_auth != SADB_X_AALG_NULL &&
 	    ((key->sadb_key_bits+7) / 8 == 0 ||
 	     (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
 		return ERR_PTR(-EINVAL);
diff -urN linux-2.5.65-bk1/net/netsyms.c linux-2.5.65-bk2/net/netsyms.c
--- linux-2.5.65-bk1/net/netsyms.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/net/netsyms.c	Mon Mar 31 12:39:51 2003
@@ -547,6 +547,8 @@
 EXPORT_SYMBOL(unregister_netdevice);
 EXPORT_SYMBOL(netdev_state_change);
 EXPORT_SYMBOL(dev_new_index);
+EXPORT_SYMBOL(dev_get_by_flags);
+EXPORT_SYMBOL(__dev_get_by_flags);
 EXPORT_SYMBOL(dev_get_by_index);
 EXPORT_SYMBOL(__dev_get_by_index);
 EXPORT_SYMBOL(dev_get_by_name);
diff -urN linux-2.5.65-bk1/net/nonet.c linux-2.5.65-bk2/net/nonet.c
--- linux-2.5.65-bk1/net/nonet.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/net/nonet.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,28 @@
+/*
+ * net/nonet.c
+ *
+ * Dummy functions to allow us to configure network support entirely
+ * out of the kernel.
+ *
+ * Distributed under the terms of the GNU GPL version 2.
+ * Copyright (c) Matthew Wilcox 2003
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+void __init sock_init(void)
+{
+	printk(KERN_INFO "Linux NoNET1.0 for Linux 2.6\n");
+}
+
+static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
+{
+	return -ENXIO;
+}
+
+struct file_operations bad_sock_fops = {
+	.open = sock_no_open,
+};
diff -urN linux-2.5.65-bk1/net/sched/sch_atm.c linux-2.5.65-bk2/net/sched/sch_atm.c
--- linux-2.5.65-bk1/net/sched/sch_atm.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/net/sched/sch_atm.c	Mon Mar 31 12:39:51 2003
@@ -508,7 +508,7 @@
 			ATM_SKB(skb)->vcc = flow->vcc;
 			memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
 			    flow->hdr_len);
-			atomic_add(skb->truesize,&flow->vcc->tx_inuse);
+			atomic_add(skb->truesize,&flow->vcc->sk->wmem_alloc);
 			ATM_SKB(skb)->iovcnt = 0;
 			/* atm.atm_options are already set by atm_tc_enqueue */
 			(void) flow->vcc->send(flow->vcc,skb);
diff -urN linux-2.5.65-bk1/net/sctp/associola.c linux-2.5.65-bk2/net/sctp/associola.c
--- linux-2.5.65-bk1/net/sctp/associola.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/net/sctp/associola.c	Mon Mar 31 12:39:51 2003
@@ -181,7 +181,7 @@
 	else
 		asoc->rwnd = sk->rcvbuf;
 
-	asoc->a_rwnd = 0;
+	asoc->a_rwnd = asoc->rwnd;
 
 	asoc->rwnd_over = 0;
 
@@ -360,9 +360,25 @@
 	}
 }
 
+/* Change the primary destination address for the peer. */
+void sctp_assoc_set_primary(struct sctp_association *asoc,
+			    struct sctp_transport *transport)
+{
+	asoc->peer.primary_path = transport;
+
+	/* Set a default msg_name for events. */
+	memcpy(&asoc->peer.primary_addr, &transport->ipaddr,
+	       sizeof(union sctp_addr));
+
+	/* If the primary path is changing, assume that the
+	 * user wants to use this new path.
+	 */
+	if (transport->active)
+		asoc->peer.active_path = transport;
+}
 
 /* Add a transport address to an association.  */
-struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
+struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
 					   const union sctp_addr *addr,
 					   int priority)
 {
@@ -397,17 +413,16 @@
 	 * If not and the current association PMTU is higher than the new
 	 * peer's PMTU, reset the association PMTU to the new peer's PMTU.
 	 */
-	if (asoc->pmtu) {
+	if (asoc->pmtu)
 		asoc->pmtu = min_t(int, peer->pmtu, asoc->pmtu);
-	} else {
+	else
 		asoc->pmtu = peer->pmtu;
-	}
 
 	SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "
 			  "%d\n", asoc, asoc->pmtu);
 
-	asoc->frag_point = asoc->pmtu -
-		(SCTP_IP_OVERHEAD + sizeof(sctp_data_chunk_t));
+	asoc->frag_point = asoc->pmtu;
+	asoc->frag_point -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
 
 	/* The asoc->peer.port might not be meaningful yet, but
 	 * initialize the packet structure anyway.
@@ -460,11 +475,7 @@
 
 	/* If we do not yet have a primary path, set one.  */
 	if (NULL == asoc->peer.primary_path) {
-		asoc->peer.primary_path = peer;
-		/* Set a default msg_name for events. */
-		memcpy(&asoc->peer.primary_addr, &peer->ipaddr,
-		       sizeof(union sctp_addr));
-		asoc->peer.active_path = peer;
+		sctp_assoc_set_primary(asoc, peer);
 		asoc->peer.retran_path = peer;
 	}
 
@@ -603,7 +614,7 @@
 /* Allocate the next TSN, Transmission Sequence Number, for the given
  * association.
  */
-__u32 __sctp_association_get_next_tsn(sctp_association_t *asoc)
+__u32 sctp_association_get_next_tsn(sctp_association_t *asoc)
 {
 	/* From Section 1.6 Serial Number Arithmetic:
 	 * Transmission Sequence Numbers wrap around when they reach
@@ -618,7 +629,7 @@
 }
 
 /* Allocate 'num' TSNs by incrementing the association's TSN by num. */
-__u32 __sctp_association_get_tsn_block(sctp_association_t *asoc, int num)
+__u32 sctp_association_get_tsn_block(sctp_association_t *asoc, int num)
 {
 	__u32 retval = asoc->next_tsn;
 
@@ -942,7 +953,7 @@
 {
 	/* If this is the first time SHUTDOWN is sent, use the active path,
 	 * else use the retran path. If the last SHUTDOWN was sent over the
-	 * retran path, update the retran path and use it. 
+	 * retran path, update the retran path and use it.
 	 */
 	if (!asoc->shutdown_last_sent_to)
 		return asoc->peer.active_path;
@@ -983,6 +994,24 @@
 			  __FUNCTION__, asoc, asoc->pmtu, asoc->frag_point);
 }
 
+/* Should we send a SACK to update our peer? */
+static inline int sctp_peer_needs_update(struct sctp_association *asoc)
+{
+	switch (asoc->state) {
+	case SCTP_STATE_ESTABLISHED:
+	case SCTP_STATE_SHUTDOWN_PENDING:
+	case SCTP_STATE_SHUTDOWN_RECEIVED:
+		if ((asoc->rwnd > asoc->a_rwnd) && 
+		    ((asoc->rwnd - asoc->a_rwnd) >=
+		     min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) 
+			return 1;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
 /* Increase asoc's rwnd by len and send any window update SACK if needed. */
 void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
 {
@@ -1009,10 +1038,8 @@
 	 * The algorithm used is similar to the one described in
 	 * Section 4.2.3.3 of RFC 1122.
 	 */
-	if ((asoc->state == SCTP_STATE_ESTABLISHED) &&
-	    (asoc->rwnd > asoc->a_rwnd) &&
-	    ((asoc->rwnd - asoc->a_rwnd) >=
-		     min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) {
+	if (sctp_peer_needs_update(asoc)) {
+		asoc->a_rwnd = asoc->rwnd;
 		SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p "
 				  "rwnd: %u a_rwnd: %u\n", __FUNCTION__,
 				  asoc, asoc->rwnd, asoc->a_rwnd);
@@ -1020,9 +1047,6 @@
 		if (!sack)
 			return;
 
-		/* Update the last advertised rwnd value. */
-		asoc->a_rwnd = asoc->rwnd;
-
 		asoc->peer.sack_needed = 0;
 
 		sctp_outq_tail(&asoc->outqueue, sack);
@@ -1046,7 +1070,8 @@
 		asoc->rwnd = 0;
 	}
 	SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n",
-			  __FUNCTION__, asoc, len, asoc->rwnd, asoc->rwnd_over);
+			  __FUNCTION__, asoc, len, asoc->rwnd, 
+			  asoc->rwnd_over);
 }
 
 /* Build the bind address list for the association based on info from the
diff -urN linux-2.5.65-bk1/net/sctp/bind_addr.c linux-2.5.65-bk2/net/sctp/bind_addr.c
--- linux-2.5.65-bk1/net/sctp/bind_addr.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/net/sctp/bind_addr.c	Mon Mar 31 12:39:51 2003
@@ -302,7 +302,7 @@
 static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
 			      sctp_scope_t scope, int priority, int flags)
 {
-	sctp_protocol_t *proto = sctp_get_protocol();
+	struct sctp_protocol *proto = sctp_get_protocol();
 	int error = 0;
 
 	if (sctp_is_any(addr)) {
diff -urN linux-2.5.65-bk1/net/sctp/endpointola.c linux-2.5.65-bk2/net/sctp/endpointola.c
--- linux-2.5.65-bk1/net/sctp/endpointola.c	Mon Mar 17 13:43:41 2003
+++ linux-2.5.65-bk2/net/sctp/endpointola.c	Mon Mar 31 12:39:51 2003
@@ -65,7 +65,7 @@
 /* Create a sctp_endpoint_t with all that boring stuff initialized.
  * Returns NULL if there isn't enough memory.
  */
-sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
+sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto,
 				   struct sock *sk, int priority)
 {
 	sctp_endpoint_t *ep;
@@ -89,7 +89,8 @@
 /*
  * Initialize the base fields of the endpoint structure.
  */
-sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
+sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, 
+				    struct sctp_protocol *proto,
 				    struct sock *sk, int priority)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
@@ -194,6 +195,8 @@
 {
 	SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return);
 
+	ep->base.sk->state = SCTP_SS_CLOSED;
+
 	/* Unlink this endpoint, so we can't find it again! */
 	sctp_unhash_endpoint(ep);
 
diff -urN linux-2.5.65-bk1/net/sctp/ipv6.c linux-2.5.65-bk2/net/sctp/ipv6.c
--- linux-2.5.65-bk1/net/sctp/ipv6.c	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/net/sctp/ipv6.c	Mon Mar 31 12:39:51 2003
@@ -432,6 +432,62 @@
 	return retval;
 }
 
+/* Create and initialize a new sk for the socket to be returned by accept(). */ 
+struct sock *sctp_v6_create_accept_sk(struct sock *sk,
+				      struct sctp_association *asoc)
+{
+	struct inet_opt *inet = inet_sk(sk);
+	struct sock *newsk;
+	struct inet_opt *newinet;
+	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
+	struct sctp6_sock *newsctp6sk;
+
+	newsk = sk_alloc(PF_INET6, GFP_KERNEL, sizeof(struct sctp6_sock),
+			 sk->slab);
+	if (!newsk)
+		goto out;
+
+	sock_init_data(NULL, newsk);
+
+	newsk->type = SOCK_STREAM;
+
+	newsk->prot = sk->prot;
+	newsk->no_check = sk->no_check;
+	newsk->reuse = sk->reuse;
+
+	newsk->destruct = inet_sock_destruct;
+	newsk->zapped = 0;
+	newsk->family = PF_INET6;
+	newsk->protocol = IPPROTO_SCTP;
+	newsk->backlog_rcv = sk->prot->backlog_rcv;
+
+	newsctp6sk = (struct sctp6_sock *)newsk;
+	newsctp6sk->pinet6 = &newsctp6sk->inet6;
+
+	newinet = inet_sk(newsk);
+	newnp = inet6_sk(newsk);
+
+	memcpy(newnp, np, sizeof(struct ipv6_pinfo));
+
+	ipv6_addr_copy(&newnp->daddr, &asoc->peer.primary_addr.v6.sin6_addr); 
+
+	newinet->sport = inet->sport;
+	newinet->dport = asoc->peer.port;
+	
+#ifdef INET_REFCNT_DEBUG
+	atomic_inc(&inet6_sock_nr);
+	atomic_inc(&inet_sock_nr);
+#endif
+
+	if (0 != newsk->prot->init(newsk)) {
+		inet_sock_release(newsk);
+		newsk = NULL;
+	}
+
+out:
+	return newsk;
+}
+
 /* Initialize a PF_INET6 socket msg_name. */
 static void sctp_inet6_msgname(char *msgname, int *addr_len)
 {
@@ -564,6 +620,20 @@
 	return af->available(addr);
 }
 
+/* Fill in Supported Address Type information for INIT and INIT-ACK
+ * chunks.   Note: In the future, we may want to look at sock options
+ * to determine whether a PF_INET6 socket really wants to have IPV4
+ * addresses.  
+ * Returns number of addresses supported.
+ */
+static int sctp_inet6_supported_addrs(const struct sctp_opt *opt,
+				      __u16 *types) 
+{
+	types[0] = SCTP_PARAM_IPV4_ADDRESS;
+	types[1] = SCTP_PARAM_IPV6_ADDRESS;
+	return 2;
+}
+
 static struct proto_ops inet6_seqpacket_ops = {
 	.family     = PF_INET6,
 	.release    = inet6_release,
@@ -583,7 +653,7 @@
 	.mmap       = sock_no_mmap,
 };
 
-static struct inet_protosw sctpv6_protosw = {
+static struct inet_protosw sctpv6_seqpacket_protosw = {
 	.type          = SOCK_SEQPACKET,
 	.protocol      = IPPROTO_SCTP,
 	.prot 	       = &sctp_prot,
@@ -592,6 +662,15 @@
 	.no_check      = 0,
 	.flags         = SCTP_PROTOSW_FLAG
 };
+static struct inet_protosw sctpv6_stream_protosw = {
+	.type          = SOCK_STREAM,
+	.protocol      = IPPROTO_SCTP,
+	.prot 	       = &sctp_prot,
+	.ops           = &inet6_seqpacket_ops,
+	.capability    = -1,
+	.no_check      = 0,
+	.flags         = SCTP_PROTOSW_FLAG
+};
 
 static struct inet6_protocol sctpv6_protocol = {
 	.handler      = sctp_rcv,
@@ -626,6 +705,8 @@
 	.af_supported  = sctp_inet6_af_supported,
 	.cmp_addr      = sctp_inet6_cmp_addr,
 	.bind_verify   = sctp_inet6_bind_verify,
+	.supported_addrs = sctp_inet6_supported_addrs,
+	.create_accept_sk = sctp_v6_create_accept_sk,
 	.af            = &sctp_ipv6_specific,
 };
 
@@ -636,8 +717,9 @@
 	if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
 		return -EAGAIN;
 
-	/* Add SCTPv6 to inetsw6 linked list. */
-	inet6_register_protosw(&sctpv6_protosw);
+	/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
+	inet6_register_protosw(&sctpv6_seqpacket_protosw);
+	inet6_register_protosw(&sctpv6_stream_protosw);
 
 	/* Register the SCTP specfic PF_INET6 functions. */
 	sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);
@@ -656,6 +738,7 @@
 {
 	list_del(&sctp_ipv6_specific.list);
 	inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
-	inet6_unregister_protosw(&sctpv6_protosw);
+	inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
+	inet6_unregister_protosw(&sctpv6_stream_protosw);
 	unregister_inet6addr_notifier(&sctp_inetaddr_notifier);
 }
diff -urN linux-2.5.65-bk1/net/sctp/output.c linux-2.5.65-bk2/net/sctp/output.c
--- linux-2.5.65-bk1/net/sctp/output.c	Mon Mar 17 13:43:46 2003
+++ linux-2.5.65-bk2/net/sctp/output.c	Mon Mar 31 12:39:51 2003
@@ -62,17 +62,16 @@
 #include <net/sctp/sm.h>
 
 /* Forward declarations for private helpers. */
-static void sctp_packet_reset(sctp_packet_t *packet);
-static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
-					   sctp_chunk_t *chunk);
+static void sctp_packet_reset(struct sctp_packet *packet);
+static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
+					   struct sctp_chunk *chunk);
 
 /* Config a packet.
  * This appears to be a followup set of initializations.)
  */
-sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
-				  __u32 vtag,
-				  int ecn_capable,
-				  sctp_packet_phandler_t *prepend_handler)
+struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
+				       __u32 vtag, int ecn_capable,
+				       sctp_packet_phandler_t *prepend_handler)
 {
 	int packet_empty = (packet->size == SCTP_IP_OVERHEAD);
 
@@ -89,10 +88,9 @@
 }
 
 /* Initialize the packet structure. */
-sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
-				struct sctp_transport *transport,
-				__u16 sport,
-				__u16 dport)
+struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
+				     struct sctp_transport *transport,
+				     __u16 sport, __u16 dport)
 {
 	packet->transport = transport;
 	packet->source_port = sport;
@@ -109,14 +107,12 @@
 }
 
 /* Free a packet.  */
-void sctp_packet_free(sctp_packet_t *packet)
+void sctp_packet_free(struct sctp_packet *packet)
 {
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 
-        while (NULL != 
-	       (chunk = (sctp_chunk_t *)skb_dequeue(&packet->chunks))) {
+        while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)))
 		sctp_free_chunk(chunk);
-	}
 
 	if (packet->malloced)
 		kfree(packet);
@@ -129,8 +125,8 @@
  * as it can fit in the packet, but any more data that does not fit in this
  * packet can be sent only after receiving the COOKIE_ACK.
  */
-sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet,
-				       sctp_chunk_t *chunk)
+sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
+				       struct sctp_chunk *chunk)
 {
 	sctp_xmit_t retval;
 	int error = 0;
@@ -152,6 +148,7 @@
 	case SCTP_XMIT_MUST_FRAG:
 	case SCTP_XMIT_RWND_FULL:
 	case SCTP_XMIT_OK:
+	case SCTP_XMIT_NAGLE_DELAY:
 		break;
 	};
 
@@ -161,7 +158,8 @@
 /* Append a chunk to the offered packet reporting back any inability to do
  * so.
  */
-sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
+sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
+				     struct sctp_chunk *chunk)
 {
 	sctp_xmit_t retval = SCTP_XMIT_OK;
 	__u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length));
@@ -182,7 +180,7 @@
 		/* Both control chunks and data chunks with TSNs are
 		 * non-fragmentable.
 		 */
-		int fragmentable = sctp_chunk_is_data(chunk) && 
+		int fragmentable = sctp_chunk_is_data(chunk) &&
 			(!chunk->has_tsn);
 		if (packet_empty) {
 			if (fragmentable) {
@@ -223,7 +221,7 @@
 	}
 
 	/* It is OK to send this chunk.  */
-	skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
+	__skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
 	packet->size += chunk_len;
 finish:
 	return retval;
@@ -234,18 +232,18 @@
  *
  * The return value is a normal kernel error return value.
  */
-int sctp_packet_transmit(sctp_packet_t *packet)
+int sctp_packet_transmit(struct sctp_packet *packet)
 {
 	struct sctp_transport *transport = packet->transport;
-	sctp_association_t *asoc = transport->asoc;
+	struct sctp_association *asoc = transport->asoc;
 	struct sctphdr *sh;
 	__u32 crc32;
 	struct sk_buff *nskb;
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 	struct sock *sk;
 	int err = 0;
 	int padding;		/* How much padding do we need?  */
-	__u8 packet_has_data = 0;
+	__u8 has_data = 0;
 	struct dst_entry *dst;
 
 	/* Do NOT generate a chunkless packet... */
@@ -253,7 +251,7 @@
 		return err;
 
 	/* Set up convenience variables... */
-	chunk = (sctp_chunk_t *) (packet->chunks.next);
+	chunk = (struct sctp_chunk *) (packet->chunks.next);
 	sk = chunk->skb->sk;
 
 	/* Allocate the new skb.  */
@@ -291,8 +289,7 @@
 	 * [This whole comment explains WORD_ROUND() below.]
 	 */
 	SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
-	while (NULL != (chunk = (sctp_chunk_t *)
-			skb_dequeue(&packet->chunks))) {
+	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
 		chunk->num_times_sent++;
 		chunk->sent_at = jiffies;
 		if (sctp_chunk_is_data(chunk)) {
@@ -309,7 +306,7 @@
 				chunk->rtt_in_progress = 1;
 				transport->rto_pending = 1;
 			}
-			packet_has_data = 1;
+			has_data = 1;
 		}
 		memcpy(skb_put(nskb, chunk->skb->len),
 		       chunk->skb->data, chunk->skb->len);
@@ -399,7 +396,7 @@
 		asoc->peer.last_sent_to = transport;
 	}
 
-	if (packet_has_data) {
+	if (has_data) {
 		struct timer_list *timer;
 		unsigned long timeout;
 
@@ -456,9 +453,9 @@
 /*
  * This private function resets the packet to a fresh state.
  */
-static void sctp_packet_reset(sctp_packet_t *packet)
+static void sctp_packet_reset(struct sctp_packet *packet)
 {
-	sctp_chunk_t *chunk = NULL;
+	struct sctp_chunk *chunk = NULL;
 
 	packet->size = SCTP_IP_OVERHEAD;
 
@@ -473,13 +470,16 @@
 }
 
 /* This private function handles the specifics of appending DATA chunks.  */
-static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, 
-					   sctp_chunk_t *chunk)
+static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
+					   struct sctp_chunk *chunk)
 {
 	sctp_xmit_t retval = SCTP_XMIT_OK;
 	size_t datasize, rwnd, inflight;
 	struct sctp_transport *transport = packet->transport;
 	__u32 max_burst_bytes;
+	struct sctp_association *asoc = transport->asoc;
+	struct sctp_opt *sp = sctp_sk(asoc->base.sk);
+	struct sctp_outq *q = &asoc->outqueue;
 
 	/* RFC 2960 6.1  Transmission of DATA Chunks
 	 *
@@ -494,8 +494,8 @@
 	 * receiver to the data sender.
 	 */
 
-	rwnd = transport->asoc->peer.rwnd;
-	inflight = transport->asoc->outqueue.outstanding_bytes;
+	rwnd = asoc->peer.rwnd;
+	inflight = asoc->outqueue.outstanding_bytes;
 
 	datasize = sctp_data_size(chunk);
 
@@ -517,7 +517,7 @@
 	 * 	if ((flightsize + Max.Burst * MTU) < cwnd)
 	 *		cwnd = flightsize + Max.Burst * MTU
 	 */
-	max_burst_bytes = transport->asoc->max_burst * transport->asoc->pmtu;
+	max_burst_bytes = asoc->max_burst * asoc->pmtu;
 	if ((transport->flight_size + max_burst_bytes) < transport->cwnd) {
 		transport->cwnd = transport->flight_size + max_burst_bytes;
 		SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: "
@@ -543,27 +543,44 @@
 	 *    When a Fast Retransmit is being performed the sender SHOULD
 	 *    ignore the value of cwnd and SHOULD NOT delay retransmission.
 	 */
-	if (!chunk->fast_retransmit) {
+	if (!chunk->fast_retransmit)
 		if (transport->flight_size >= transport->cwnd) {
 			retval = SCTP_XMIT_RWND_FULL;
 			goto finish;
 		}
+
+	/* Nagle's algorithm to solve small-packet problem:
+	 * Inhibit the sending of new chunks when new outgoing data arrives
+	 * if any previously transmitted data on the connection remains
+	 * unacknowledged.
+	 */
+	if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && 
+	    q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) {
+		unsigned len = datasize + q->out_qlen;
+
+		/* Check whether this chunk and all the rest of pending
+		 * data will fit or delay in hopes of bundling a full
+		 * sized packet.
+		 */
+		if (len < asoc->pmtu - SCTP_IP_OVERHEAD) {
+			retval = SCTP_XMIT_NAGLE_DELAY;
+			goto finish;
+		}
 	}
 
 	/* Keep track of how many bytes are in flight over this transport. */
 	transport->flight_size += datasize;
 
 	/* Keep track of how many bytes are in flight to the receiver. */
-	transport->asoc->outqueue.outstanding_bytes += datasize;
+	asoc->outqueue.outstanding_bytes += datasize;
 
 	/* Update our view of the receiver's rwnd. */
-	if (datasize < rwnd) {
+	if (datasize < rwnd)
 		rwnd -= datasize;
-	} else {
+	else
 		rwnd = 0;
-	}
 
-	transport->asoc->peer.rwnd = rwnd;
+	asoc->peer.rwnd = rwnd;
 
 finish:
 	return retval;
diff -urN linux-2.5.65-bk1/net/sctp/outqueue.c linux-2.5.65-bk2/net/sctp/outqueue.c
--- linux-2.5.65-bk1/net/sctp/outqueue.c	Mon Mar 17 13:44:01 2003
+++ linux-2.5.65-bk2/net/sctp/outqueue.c	Mon Mar 31 12:39:51 2003
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001-2003 Intel Corp.
  * Copyright (c) 2001-2003 International Business Machines Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
@@ -62,6 +62,43 @@
 				   sctp_sackhdr_t *sack,
 				   __u32 highest_new_tsn);
 
+/* Add data to the front of the queue. */
+static inline void sctp_outq_head_data(struct sctp_outq *q,
+					struct sctp_chunk *ch)
+{
+	__skb_queue_head(&q->out, (struct sk_buff *)ch);
+	q->out_qlen += ch->skb->len;
+	return;
+}
+
+/* Take data from the front of the queue. */
+static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q)
+{
+	struct sctp_chunk *ch;
+	ch = (struct sctp_chunk *)__skb_dequeue(&q->out);
+	if (ch)
+		q->out_qlen -= ch->skb->len;
+	return ch;
+}
+/* Add data chunk to the end of the queue. */
+static inline void sctp_outq_tail_data(struct sctp_outq *q,
+				       struct sctp_chunk *ch)
+{
+	__skb_queue_tail(&q->out, (struct sk_buff *)ch);
+	q->out_qlen += ch->skb->len;
+	return;
+}
+
+/* Insert a chunk behind chunk 'pos'. */
+static inline void sctp_outq_insert_data(struct sctp_outq *q,
+					 struct sctp_chunk *ch,
+					 struct sctp_chunk *pos)
+{
+	__skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev, 
+		     (struct sk_buff *)pos, pos->list);
+	q->out_qlen += ch->skb->len;
+}
+
 /* Generate a new outqueue.  */
 struct sctp_outq *sctp_outq_new(sctp_association_t *asoc)
 {
@@ -97,6 +134,7 @@
 	q->empty = 1;
 
 	q->malloced = 0;
+	q->out_qlen = 0;
 }
 
 /* Free the outqueue structure and any related pending chunks.
@@ -125,7 +163,7 @@
 		sctp_free_chunk(chunk);
 	}
 
-	/* Throw away any chunks in the retransmit queue. */ 
+	/* Throw away any chunks in the retransmit queue. */
 	list_for_each_safe(lchunk, temp, &q->retransmit) {
 		list_del(lchunk);
 		chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
@@ -133,7 +171,7 @@
 	}
 
 	/* Throw away any leftover data chunks. */
-	while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->out)))
+	while ((chunk = sctp_outq_dequeue_data(q)))
 		sctp_free_chunk(chunk);
 
 	/* Throw away any leftover control chunks. */
@@ -192,7 +230,7 @@
 			  sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type))
 			  : "Illegal Chunk");
 
-			skb_queue_tail(&q->out, (struct sk_buff *) chunk);
+			sctp_outq_tail_data(q, chunk);
 			if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
 				SCTP_INC_STATS(SctpOutUnorderChunks);
 			else
@@ -201,7 +239,7 @@
 			break;
 		};
 	} else {
-		skb_queue_tail(&q->control, (struct sk_buff *) chunk);
+		__skb_queue_tail(&q->control, (struct sk_buff *) chunk);
 		SCTP_INC_STATS(SctpOutCtrlChunks);
 	}
 
@@ -241,7 +279,7 @@
 }
 
 /* Mark all the eligible packets on a transport for retransmission.  */
-void sctp_retransmit_mark(struct sctp_outq *q, 
+void sctp_retransmit_mark(struct sctp_outq *q,
 			  struct sctp_transport *transport,
 			  __u8 fast_retransmit)
 {
@@ -351,7 +389,7 @@
  *
  * The return value is a normal kernel error return value.
  */
-static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt,
+static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
 			       int rtx_timeout, int *start_timer)
 {
 	struct list_head *lqueue;
@@ -385,17 +423,6 @@
 
 	while (lchunk) {
 		chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
-#if 0
-		/* If a chunk has been tried for more than SCTP_DEF_MAX_SEND
-		 * times, discard it, and check the empty flag of the outqueue.
-		 *
-		 * --xguo
-		 */
-		if (chunk->snd_count > SCTP_DEF_MAX_SEND) {
-			sctp_free_chunk(chunk);
-			continue;
-		}
-#endif
 
 		/* Make sure that Gap Acked TSNs are not retransmitted.  A
 		 * simple approach is just to move such TSNs out of the
@@ -461,8 +488,8 @@
  * queue.  'pos' points to the next chunk in the output queue after the
  * chunk that is currently in the process of fragmentation.
  */
-void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
-		    sctp_packet_t *packet, sctp_chunk_t *frag, __u32 tsn)
+void sctp_xmit_frag(struct sctp_outq *q, struct sctp_chunk *pos,
+		struct sctp_packet *packet, struct sctp_chunk *frag, __u32 tsn)
 {
 	struct sctp_transport *transport = packet->transport;
 	struct sk_buff_head *queue = &q->out;
@@ -480,11 +507,10 @@
 		SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. "
 				  "adding 0x%x to outqueue\n",
 				  ntohl(frag->subh.data_hdr->tsn));
-		if (pos) {
-			skb_insert(pos, (struct sk_buff *) frag);
-		} else {
-			skb_queue_tail(queue, (struct sk_buff *) frag);
-		}
+		if (pos)		
+			sctp_outq_insert_data(q, frag, pos);
+		else
+			sctp_outq_tail_data(q, frag);
 		return;
 	}
 
@@ -496,11 +522,10 @@
 		SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. "
 				  "adding 0x%x to outqueue\n",
 				  ntohl(frag->subh.data_hdr->tsn));
-		if (pos) {
-			skb_insert(pos, (struct sk_buff *) frag);
-		} else {
-			skb_queue_tail(queue, (struct sk_buff *) frag);
-		}
+		if (pos)
+			sctp_outq_insert_data(q, frag, pos);
+		else
+			sctp_outq_tail_data(q, frag);
 		break;
 
 	case SCTP_XMIT_OK:
@@ -512,11 +537,10 @@
 			SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output "
 					  "failed. adding 0x%x to outqueue\n",
 					  ntohl(frag->subh.data_hdr->tsn));
-			if (pos) {
-				skb_insert(pos, (struct sk_buff *) frag);
-			} else {
-				skb_queue_tail(queue, (struct sk_buff *) frag);
-			}
+			if (pos)
+				sctp_outq_insert_data(q, frag, pos);
+			else
+				sctp_outq_tail_data(q, frag);
 		} else {
 			SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output "
 					  "success. 0x%x sent\n",
@@ -537,14 +561,14 @@
  * The argument 'frag' point to the first fragment and it holds the list
  * of all the other fragments in the 'frag_list' field.
  */
-void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet,
+void sctp_xmit_fragmented_chunks(struct sctp_outq *q, struct sctp_packet *pkt,
 				 sctp_chunk_t *frag)
 {
 	sctp_association_t *asoc = frag->asoc;
 	struct list_head *lfrag, *frag_list;
 	__u32 tsn;
 	int nfrags = 1;
-	struct sk_buff *pos;
+	struct sctp_chunk *pos;
 
 	/* Count the number of fragments. */
 	frag_list = &frag->frag_list;
@@ -553,17 +577,17 @@
 	}
 
 	/* Get a TSN block of nfrags TSNs. */
-	tsn = __sctp_association_get_tsn_block(asoc, nfrags);
+	tsn = sctp_association_get_tsn_block(asoc, nfrags);
 
-	pos = skb_peek(&q->out);
+	pos = (struct sctp_chunk *)skb_peek(&q->out);
 	/* Transmit the first fragment. */
-	sctp_xmit_frag(q, pos, packet, frag, tsn++);
+	sctp_xmit_frag(q, pos, pkt, frag, tsn++);
 
 	/* Transmit the rest of fragments. */
 	frag_list = &frag->frag_list;
 	list_for_each(lfrag, frag_list) {
 		frag = list_entry(lfrag, sctp_chunk_t, frag_list);
-		sctp_xmit_frag(q, pos, packet, frag, tsn++);
+		sctp_xmit_frag(q, pos, pkt, frag, tsn++);
 	}
 }
 
@@ -595,7 +619,7 @@
  	old_flags = chunk->chunk_hdr->flags;
 	if (old_flags & SCTP_DATA_FIRST_FRAG)
 		flags = SCTP_DATA_FIRST_FRAG;
-	else 
+	else
 		flags = SCTP_DATA_MIDDLE_FRAG;
 
 	/* Make the first fragment. */
@@ -672,15 +696,14 @@
  *
  * Description: Send everything in q which we legally can, subject to
  * congestion limitations.
- *
- * Note: This function can be called from multiple contexts so appropriate
+ * * Note: This function can be called from multiple contexts so appropriate
  * locking concerns must be made.  Today we use the sock lock to protect
  * this function.
  */
 int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
 {
-	sctp_packet_t *packet;
-	sctp_packet_t singleton;
+	struct sctp_packet *packet;
+	struct sctp_packet singleton;
 	sctp_association_t *asoc = q->asoc;
 	int ecn_capable = asoc->peer.ecn_capable;
 	__u16 sport = asoc->base.bind_addr.port;
@@ -719,7 +742,7 @@
 	}
 
 	queue = &q->control;
-	while (NULL != (chunk = (sctp_chunk_t *)skb_dequeue(queue))) {
+	while ((chunk = (sctp_chunk_t *)skb_dequeue(queue))) {
 		/* Pick the right transport to use. */
 		new_transport = chunk->transport;
 
@@ -852,7 +875,8 @@
 		/* Finally, transmit new packets.  */
 		start_timer = 0;
 		queue = &q->out;
-		while (NULL != (chunk = (sctp_chunk_t *) skb_dequeue(queue))) {
+
+		while (NULL != (chunk = sctp_outq_dequeue_data(q))) {
 			/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
 			 * stream identifier.
 			 */
@@ -925,6 +949,7 @@
 			switch (status) {
 			case SCTP_XMIT_PMTU_FULL:
 			case SCTP_XMIT_RWND_FULL:
+			case SCTP_XMIT_NAGLE_DELAY:
 				/* We could not append this chunk, so put
 				 * the chunk back on the output queue.
 				 */
@@ -932,7 +957,7 @@
 					"not transmit TSN: 0x%x, status: %d\n",
 					ntohl(chunk->subh.data_hdr->tsn),
 					status);
-				skb_queue_head(queue, (struct sk_buff *)chunk);
+				sctp_outq_head_data(q, chunk);
 				goto sctp_flush_out;
 				break;
 
@@ -994,6 +1019,7 @@
 	}
 
 sctp_flush_out:
+
 	/* Before returning, examine all the transports touched in
 	 * this call.  Right now, we bluntly force clear all the
 	 * transports.  Things might change after we implement Nagle.
@@ -1003,7 +1029,7 @@
 	 */
 	while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL ) {
 		struct sctp_transport *t = list_entry(ltransport,
-						      struct sctp_transport, 
+						      struct sctp_transport,
 						      send_ready);
 		if (t != transport)
 			transport = t;
@@ -1125,7 +1151,7 @@
 	 * This is a MASSIVE candidate for optimization.
 	 */
 	list_for_each(pos, transport_list) {
-		transport  = list_entry(pos, struct sctp_transport, 
+		transport  = list_entry(pos, struct sctp_transport,
 					transports);
 		sctp_check_transmitted(q, &transport->transmitted,
 				       transport, sack, highest_new_tsn);
@@ -1163,11 +1189,10 @@
 	sack_a_rwnd = ntohl(sack->a_rwnd);
 	outstanding = q->outstanding_bytes;
 
-	if (outstanding < sack_a_rwnd) {
+	if (outstanding < sack_a_rwnd)
 		sack_a_rwnd -= outstanding;
-	} else {
+	else
 		sack_a_rwnd = 0;
-	}
 
 	asoc->peer.rwnd = sack_a_rwnd;
 
@@ -1179,7 +1204,7 @@
 		goto finish;
 
 	list_for_each(pos, transport_list) {
-		transport  = list_entry(pos, struct sctp_transport, 
+		transport  = list_entry(pos, struct sctp_transport,
 					transports);
 		q->empty = q->empty && list_empty(&transport->transmitted);
 		if (!q->empty)
diff -urN linux-2.5.65-bk1/net/sctp/protocol.c linux-2.5.65-bk2/net/sctp/protocol.c
--- linux-2.5.65-bk1/net/sctp/protocol.c	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/net/sctp/protocol.c	Mon Mar 31 12:39:51 2003
@@ -58,7 +58,7 @@
 #include <net/inet_common.h>
 
 /* Global data structures. */
-sctp_protocol_t sctp_proto;
+struct sctp_protocol sctp_proto;
 struct proc_dir_entry	*proc_net_sctp;
 DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics);
 
@@ -152,7 +152,7 @@
 /* Extract our IP addresses from the system and stash them in the
  * protocol structure.
  */
-static void __sctp_get_local_addr_list(sctp_protocol_t *proto)
+static void __sctp_get_local_addr_list(struct sctp_protocol *proto)
 {
 	struct net_device *dev;
 	struct list_head *pos;
@@ -168,7 +168,7 @@
 	read_unlock(&dev_base_lock);
 }
 
-static void sctp_get_local_addr_list(sctp_protocol_t *proto)
+static void sctp_get_local_addr_list(struct sctp_protocol *proto)
 {
 	long flags __attribute__ ((unused));
 
@@ -178,7 +178,7 @@
 }
 
 /* Free the existing local addresses.  */
-static void __sctp_free_local_addr_list(sctp_protocol_t *proto)
+static void __sctp_free_local_addr_list(struct sctp_protocol *proto)
 {
 	struct sockaddr_storage_list *addr;
 	struct list_head *pos, *temp;
@@ -191,7 +191,7 @@
 }
 
 /* Free the existing local addresses.  */
-static void sctp_free_local_addr_list(sctp_protocol_t *proto)
+static void sctp_free_local_addr_list(struct sctp_protocol *proto)
 {
 	long flags __attribute__ ((unused));
 
@@ -201,8 +201,9 @@
 }
 
 /* Copy the local addresses which are valid for 'scope' into 'bp'.  */
-int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
-			      sctp_scope_t scope, int priority, int copy_flags)
+int sctp_copy_local_addr_list(struct sctp_protocol *proto,
+			      struct sctp_bind_addr *bp, sctp_scope_t scope,
+			      int priority, int copy_flags)
 {
 	struct sockaddr_storage_list *addr;
 	int error = 0;
@@ -331,7 +332,7 @@
 static int sctp_v4_available(const union sctp_addr *addr)
 {
 	int ret = inet_addr_type(addr->v4.sin_addr.s_addr);
-	
+
 	/* FIXME: ip_nonlocal_bind sysctl support. */
 
 	if (addr->v4.sin_addr.s_addr != INADDR_ANY && ret != RTN_LOCAL)
@@ -380,7 +381,7 @@
 
 /* Returns a valid dst cache entry for the given source and destination ip
  * addresses. If an association is passed, trys to get a dst entry with a
- * source adddress that matches an address in the bind address list. 
+ * source adddress that matches an address in the bind address list.
  */
 struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc,
 				  union sctp_addr *daddr,
@@ -479,6 +480,61 @@
 
 }
 
+/* Create and initialize a new sk for the socket returned by accept(). */ 
+struct sock *sctp_v4_create_accept_sk(struct sock *sk,
+				      struct sctp_association *asoc)
+{
+	struct sock *newsk;
+	struct inet_opt *inet = inet_sk(sk);
+	struct inet_opt *newinet;
+
+	newsk = sk_alloc(PF_INET, GFP_KERNEL, sizeof(struct sctp_sock),
+			 sk->slab);
+	if (!newsk)
+		goto out;
+
+	sock_init_data(NULL, newsk);
+
+	newsk->type = SOCK_STREAM;
+
+	newsk->prot = sk->prot;
+	newsk->no_check = sk->no_check;
+	newsk->reuse = sk->reuse;
+
+	newsk->destruct = inet_sock_destruct;
+	newsk->zapped = 0;
+	newsk->family = PF_INET;
+	newsk->protocol = IPPROTO_SCTP;
+	newsk->backlog_rcv = sk->prot->backlog_rcv;
+	
+	newinet = inet_sk(newsk);
+	newinet->sport = inet->sport;
+	newinet->saddr = inet->saddr;
+	newinet->rcv_saddr = inet->saddr;
+	newinet->dport = asoc->peer.port;
+	newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
+	newinet->pmtudisc = inet->pmtudisc;
+      	newinet->id = 0;
+	
+	newinet->ttl = sysctl_ip_default_ttl;
+	newinet->mc_loop = 1;
+	newinet->mc_ttl = 1;
+	newinet->mc_index = 0;
+	newinet->mc_list = NULL;
+
+#ifdef INET_REFCNT_DEBUG
+	atomic_inc(&inet_sock_nr);
+#endif
+
+	if (0 != newsk->prot->init(newsk)) {
+		inet_sock_release(newsk);
+		newsk = NULL;
+	}
+
+out:
+	return newsk;
+}
+
 /* Event handler for inet address addition/deletion events.
  * Basically, whenever there is an event, we re-build our local address list.
  */
@@ -501,10 +557,13 @@
  */
 int sctp_ctl_sock_init(void)
 {
-	int err = 0;
-	int family = PF_INET;
+	int err;
+	sa_family_t family;
 
-	SCTP_V6(family = PF_INET6;)
+	if (sctp_get_pf_specific(PF_INET6))
+		family = PF_INET6;
+	else 
+		family = PF_INET;
 
 	err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP,
 			  &sctp_ctl_socket);
@@ -630,6 +689,16 @@
 	return sctp_v4_available(addr);
 }
 
+/* Fill in Supported Address Type information for INIT and INIT-ACK
+ * chunks.  Returns number of addresses supported.
+ */
+static int sctp_inet_supported_addrs(const struct sctp_opt *opt, 
+				     __u16 *types)
+{
+	types[0] = SCTP_PARAM_IPV4_ADDRESS;
+	return 1;
+}
+
 /* Wrapper routine that calls the ip transmit routine. */
 static inline int sctp_v4_xmit(struct sk_buff *skb,
 			       struct sctp_transport *transport, int ipfragok)
@@ -652,6 +721,8 @@
 	.af_supported  = sctp_inet_af_supported,
 	.cmp_addr      = sctp_inet_cmp_addr,
 	.bind_verify   = sctp_inet_bind_verify,
+	.supported_addrs = sctp_inet_supported_addrs,
+	.create_accept_sk = sctp_v4_create_accept_sk,
 	.af            = &sctp_ipv4_specific,
 };
 
@@ -682,7 +753,7 @@
 };
 
 /* Registration with AF_INET family.  */
-struct inet_protosw sctp_protosw = {
+static struct inet_protosw sctp_seqpacket_protosw = {
 	.type       = SOCK_SEQPACKET,
 	.protocol   = IPPROTO_SCTP,
 	.prot       = &sctp_prot,
@@ -691,6 +762,15 @@
 	.no_check   = 0,
 	.flags      = SCTP_PROTOSW_FLAG
 };
+static struct inet_protosw sctp_stream_protosw = {
+	.type       = SOCK_STREAM,
+	.protocol   = IPPROTO_SCTP,
+	.prot       = &sctp_prot,
+	.ops        = &inet_seqpacket_ops,
+	.capability = -1,
+	.no_check   = 0,
+	.flags      = SCTP_PROTOSW_FLAG
+};
 
 /* Register with IP layer.  */
 static struct inet_protocol sctp_protocol = {
@@ -756,7 +836,7 @@
 static int __init init_sctp_mibs(void)
 {
 	int i;
-	
+
 	sctp_statistics[0] = kmalloc_percpu(sizeof (struct sctp_mib),
 					    GFP_KERNEL);
 	if (!sctp_statistics[0])
@@ -778,7 +858,7 @@
 		}
 	}
 	return 0;
-	
+
 }
 
 static void cleanup_sctp_mibs(void)
@@ -797,14 +877,15 @@
 	if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
 		return -EAGAIN;
 
-	/* Add SCTP to inetsw linked list.  */
-	inet_register_protosw(&sctp_protosw);
+	/* Add SCTP(TCP and UDP style) to inetsw linked list.  */
+	inet_register_protosw(&sctp_seqpacket_protosw);
+	inet_register_protosw(&sctp_stream_protosw);
 
 	/* Allocate and initialise sctp mibs.  */
 	status = init_sctp_mibs();
-	if (status) 
+	if (status)
 		goto err_init_mibs;
-		
+
 	/* Initialize proc fs directory.  */
 	sctp_proc_init();
 
@@ -831,7 +912,7 @@
 	/* Valid.Cookie.Life        - 60  seconds */
 	sctp_proto.valid_cookie_life	= 60 * HZ;
 
-	/* Whether Cookie Preservative is enabled(1) or not(0) */ 
+	/* Whether Cookie Preservative is enabled(1) or not(0) */
 	sctp_proto.cookie_preserve_enable = 1;
 
 	/* Max.Burst		    - 4 */
@@ -920,7 +1001,7 @@
 	INIT_LIST_HEAD(&sctp_proto.local_addr_list);
 	sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED;
 
-	/* Register notifier for inet address additions/deletions. */ 
+	/* Register notifier for inet address additions/deletions. */
 	register_inetaddr_notifier(&sctp_inetaddr_notifier);
 
 	sctp_get_local_addr_list(&sctp_proto);
@@ -942,9 +1023,10 @@
 	sctp_dbg_objcnt_exit();
 	sctp_proc_exit();
 	cleanup_sctp_mibs();
-err_init_mibs:	
+err_init_mibs:
 	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
-	inet_unregister_protosw(&sctp_protosw);
+	inet_unregister_protosw(&sctp_seqpacket_protosw);
+	inet_unregister_protosw(&sctp_stream_protosw);
 	return status;
 }
 
@@ -977,7 +1059,8 @@
 	cleanup_sctp_mibs();
 
 	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
-	inet_unregister_protosw(&sctp_protosw);
+	inet_unregister_protosw(&sctp_seqpacket_protosw);
+	inet_unregister_protosw(&sctp_stream_protosw);
 }
 
 module_init(sctp_init);
diff -urN linux-2.5.65-bk1/net/sctp/sm_make_chunk.c linux-2.5.65-bk2/net/sctp/sm_make_chunk.c
--- linux-2.5.65-bk1/net/sctp/sm_make_chunk.c	Mon Mar 17 13:43:42 2003
+++ linux-2.5.65-bk2/net/sctp/sm_make_chunk.c	Mon Mar 31 12:39:51 2003
@@ -68,29 +68,6 @@
 
 /* RFC 2960 3.3.2 Initiation (INIT) (1)
  *
- * Note 4: This parameter, when present, specifies all the
- * address types the sending endpoint can support. The absence
- * of this parameter indicates that the sending endpoint can
- * support any address type.
- */
-static const sctp_supported_addrs_param_t sat_param = {
-	{
-		SCTP_PARAM_SUPPORTED_ADDRESS_TYPES,
-		__constant_htons(SCTP_SAT_LEN),
-	}
-};
-
-/* gcc 3.2 doesn't allow initialization of zero-length arrays. So the above
- * structure is split and the address types array is initialized using a
- * fixed length array.
- */
-static const __u16 sat_addr_types[2] = {
-	SCTP_PARAM_IPV4_ADDRESS,
-	SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,)
-};
-
-/* RFC 2960 3.3.2 Initiation (INIT) (1)
- *
  * Note 2: The ECN capable field is reserved for future use of
  * Explicit Congestion Notification.
  */
@@ -174,7 +151,10 @@
 	union sctp_params addrs;
 	size_t chunksize;
 	sctp_chunk_t *retval = NULL;
-	int addrs_len = 0;
+	int num_types, addrs_len = 0;
+	struct sctp_opt *sp;
+	sctp_supported_addrs_param_t sat;
+	__u16 types[2];
 
 	/* RFC 2960 3.3.2 Initiation (INIT) (1)
 	 *
@@ -195,7 +175,11 @@
 	init.num_inbound_streams   = htons(asoc->c.sinit_max_instreams);
 	init.initial_tsn	   = htonl(asoc->c.initial_tsn);
 
-	chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN;
+	/* How many address types are needed? */
+	sp = sctp_sk(asoc->base.sk);
+	num_types = sp->pf->supported_addrs(sp, types);
+
+	chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types);
 	chunksize += sizeof(ecap_param);
 	chunksize += vparam_len;
 
@@ -220,8 +204,18 @@
 	retval->param_hdr.v =
 		sctp_addto_chunk(retval, addrs_len, addrs.v);
 
-	sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &sat_param);
-	sctp_addto_chunk(retval, sizeof(sat_addr_types), sat_addr_types);
+	/* RFC 2960 3.3.2 Initiation (INIT) (1)
+	 *
+	 * Note 4: This parameter, when present, specifies all the
+	 * address types the sending endpoint can support. The absence
+	 * of this parameter indicates that the sending endpoint can
+	 * support any address type.
+	 */
+	sat.param_hdr.type = SCTP_PARAM_SUPPORTED_ADDRESS_TYPES;
+	sat.param_hdr.length = htons(SCTP_SAT_LEN(num_types));
+	sctp_addto_chunk(retval, sizeof(sat), &sat);
+	sctp_addto_chunk(retval, num_types * sizeof(__u16), &types);
+
 	sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
 nodata:
 	if (addrs.v)
@@ -604,7 +598,7 @@
 
 	/* Initialize the SACK header.  */
 	sack.cum_tsn_ack	    = htonl(ctsn);
-	sack.a_rwnd 		    = htonl(asoc->rwnd);
+	sack.a_rwnd 		    = htonl(asoc->a_rwnd);
 	sack.num_gap_ack_blocks     = htons(num_gabs);
 	sack.num_dup_tsns           = htons(num_dup_tsns);
 
@@ -1159,7 +1153,7 @@
 	first_len = max;
 
 	/* Encourage Cookie-ECHO bundling. */
-	if (asoc->state < SCTP_STATE_ESTABLISHED) {
+	if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
 		whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN);
 
 		/* Account for the DATA to be bundled with the COOKIE-ECHO. */
@@ -1282,7 +1276,7 @@
 		 * assign a TSN.
 		 */
 		chunk->subh.data_hdr->tsn =
-			htonl(__sctp_association_get_next_tsn(chunk->asoc));
+			htonl(sctp_association_get_next_tsn(chunk->asoc));
 		chunk->has_tsn = 1;
 	}
 }
diff -urN linux-2.5.65-bk1/net/sctp/sm_sideeffect.c linux-2.5.65-bk2/net/sctp/sm_sideeffect.c
--- linux-2.5.65-bk1/net/sctp/sm_sideeffect.c	Mon Mar 17 13:44:19 2003
+++ linux-2.5.65-bk2/net/sctp/sm_sideeffect.c	Mon Mar 31 12:39:51 2003
@@ -105,8 +105,8 @@
 #define DEBUG_POST_SFX \
 	SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \
 			  error, asoc, \
-			  sctp_state_tbl[sctp_id2assoc(ep->base.sk, \
-			  sctp_assoc2id(asoc))?asoc->state:SCTP_STATE_CLOSED])
+			  sctp_state_tbl[(asoc && sctp_id2assoc(ep->base.sk, \
+			  sctp_assoc2id(asoc)))?asoc->state:SCTP_STATE_CLOSED])
 
 /*
  * This is the master state machine processing function.
@@ -256,7 +256,7 @@
 	sctp_cmd_t *cmd;
 	sctp_chunk_t *new_obj;
 	sctp_chunk_t *chunk = NULL;
-	sctp_packet_t *packet;
+	struct sctp_packet *packet;
 	struct list_head *pos;
 	struct timer_list *timer;
 	unsigned long timeout;
@@ -716,13 +716,12 @@
 		asoc->peer.sack_needed = 1;
 		goto out;
 	} else {
+		if (asoc->a_rwnd > asoc->rwnd)
+			asoc->a_rwnd = asoc->rwnd;
 		sack = sctp_make_sack(asoc);
 		if (!sack)
 			goto nomem;
 
-		/* Update the last advertised rwnd value. */
-		asoc->a_rwnd = asoc->rwnd;
-
 		asoc->peer.sack_needed = 0;
 
 		error = sctp_outq_tail(&asoc->outqueue, sack);
@@ -1223,13 +1222,35 @@
 static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
 			       sctp_state_t state)
 {
+
+	struct sock *sk = asoc->base.sk;
+	struct sctp_opt *sp = sctp_sk(sk);
+
 	asoc->state = state;
 	asoc->state_timestamp = jiffies;
 
-	/* Wake up any process waiting for the association to
-	 * get established.
+	if ((SCTP_STATE_ESTABLISHED == asoc->state) ||
+	    (SCTP_STATE_CLOSED == asoc->state)) { 
+		/* Wake up any processes waiting in the asoc's wait queue in
+		 * sctp_wait_for_connect() or sctp_wait_for_sndbuf(). 
+	 	 */
+		if (waitqueue_active(&asoc->wait))
+			wake_up_interruptible(&asoc->wait);
+
+		/* Wake up any processes waiting in the sk's sleep queue of
+		 * a TCP-style or UDP-style peeled-off socket in
+		 * sctp_wait_for_accept() or sctp_wait_for_packet().
+		 * For a UDP-style socket, the waiters are woken up by the
+		 * notifications.
+		 */
+		if (SCTP_SOCKET_UDP != sp->type)
+			sk->state_change(sk);
+	}
+
+	/* Change the sk->state of a TCP-style socket that has sucessfully
+	 * completed a connect() call.
 	 */
 	if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
-	    (waitqueue_active(&asoc->wait)))
-		wake_up_interruptible(&asoc->wait);
+	    (SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_CLOSED == sk->state))
+	    sk->state = SCTP_SS_ESTABLISHED;
 }
diff -urN linux-2.5.65-bk1/net/sctp/sm_statefuns.c linux-2.5.65-bk2/net/sctp/sm_statefuns.c
--- linux-2.5.65-bk1/net/sctp/sm_statefuns.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/net/sctp/sm_statefuns.c	Mon Mar 31 12:39:51 2003
@@ -189,7 +189,7 @@
 	sctp_chunk_t *repl;
 	sctp_association_t *new_asoc;
 	sctp_chunk_t *err_chunk;
-	sctp_packet_t *packet;
+	struct sctp_packet *packet;
 	sctp_unrecognized_param_t *unk_param;
 	int len;
 
@@ -354,10 +354,9 @@
 	sctp_init_chunk_t *initchunk;
 	__u32 init_tag;
 	sctp_chunk_t *err_chunk;
-	sctp_packet_t *packet;
+	struct sctp_packet *packet;
 	sctp_disposition_t ret;
 
-
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
@@ -912,14 +911,14 @@
 				      sctp_cmd_seq_t *commands)
 {
 	int len;
-	sctp_packet_t *pkt;
+	struct sctp_packet *pkt;
 	sctp_addr_param_t *addrparm;
 	sctp_errhdr_t *errhdr;
 	sctp_endpoint_t *ep;
 	char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)];
 
-	/* Build the error on the stack.   We are way to malloc
-	 * malloc crazy throughout the code today.
+	/* Build the error on the stack.   We are way to malloc crazy
+	 * throughout the code today.
 	 */
 	errhdr = (sctp_errhdr_t *)buffer;
 	addrparm = (sctp_addr_param_t *)errhdr->variable;
@@ -1105,11 +1104,10 @@
 	sctp_chunk_t *repl;
 	sctp_association_t *new_asoc;
 	sctp_chunk_t *err_chunk;
-	sctp_packet_t *packet;
+	struct sctp_packet *packet;
 	sctp_unrecognized_param_t *unk_param;
 	int len;
 
-
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
@@ -2351,7 +2349,7 @@
 		 * room.   Note: Playing nice with a confused sender.  A
 		 * malicious sender can still eat up all our buffer
 		 * space and in the future we may want to detect and
-		 * do more drastic reneging. 
+		 * do more drastic reneging.
 		 */
 		if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) &&
 		    (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) {
@@ -2751,7 +2749,7 @@
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
-	sctp_packet_t *packet = NULL;
+	struct sctp_packet *packet = NULL;
 	sctp_chunk_t *chunk = arg;
 	sctp_chunk_t *abort;
 
@@ -2953,7 +2951,7 @@
 				      void *arg,
 				      sctp_cmd_seq_t *commands)
 {
-	sctp_packet_t *packet = NULL;
+	struct sctp_packet *packet = NULL;
 	sctp_chunk_t *chunk = arg;
 	sctp_chunk_t *shut;
 
@@ -4377,13 +4375,13 @@
 /* Create an ABORT packet to be sent as a response, with the specified
  * error causes.
  */
-sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
+struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
 				  const sctp_association_t *asoc,
 				  sctp_chunk_t *chunk,
 				  const void *payload,
 				  size_t paylen)
 {
-	sctp_packet_t *packet;
+	struct sctp_packet *packet;
 	sctp_chunk_t *abort;
 
 	packet = sctp_ootb_pkt_new(asoc, chunk);
@@ -4413,10 +4411,10 @@
 }
 
 /* Allocate a packet for responding in the OOTB conditions.  */
-sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
+struct sctp_packet *sctp_ootb_pkt_new(const sctp_association_t *asoc,
 				 const sctp_chunk_t *chunk)
 {
-	sctp_packet_t *packet;
+	struct sctp_packet *packet;
 	struct sctp_transport *transport;
 	__u16 sport;
 	__u16 dport;
@@ -4449,7 +4447,7 @@
 		goto nomem;
 
 	/* Allocate a new packet for sending the response. */
-	packet = t_new(sctp_packet_t, GFP_ATOMIC);
+	packet = t_new(struct sctp_packet, GFP_ATOMIC);
 	if (!packet)
 		goto nomem_packet;
 
@@ -4471,7 +4469,7 @@
 }
 
 /* Free the packet allocated earlier for responding in the OOTB condition.  */
-void sctp_ootb_pkt_free(sctp_packet_t *packet)
+void sctp_ootb_pkt_free(struct sctp_packet *packet)
 {
 	sctp_transport_free(packet->transport);
 	sctp_packet_free(packet);
@@ -4484,7 +4482,7 @@
 				sctp_cmd_seq_t *commands,
 				sctp_chunk_t *err_chunk)
 {
-	sctp_packet_t *packet;
+	struct sctp_packet *packet;
 
 	if (err_chunk) {
 		packet = sctp_ootb_pkt_new(asoc, chunk);
diff -urN linux-2.5.65-bk1/net/sctp/socket.c linux-2.5.65-bk2/net/sctp/socket.c
--- linux-2.5.65-bk1/net/sctp/socket.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/net/sctp/socket.c	Mon Mar 31 12:39:51 2003
@@ -88,12 +88,46 @@
 				int msg_len);
 static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
 static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
+static int sctp_wait_for_accept(struct sock *sk, long timeo);
 static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
 static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int);
 static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int);
 static int sctp_do_bind(struct sock *, union sctp_addr *, int);
 static int sctp_autobind(struct sock *sk);
+static void sctp_sock_migrate(struct sock *, struct sock *,
+			      struct sctp_association *, sctp_socket_type_t);
 
+/* Look up the association by its id.  If this is not a UDP-style
+ * socket, the ID field is always ignored.
+ */
+sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
+{
+	sctp_association_t *asoc = NULL;
+
+	/* If this is not a UDP-style socket, assoc id should be 
+	 * ignored.
+	 */
+	if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) {
+		if (!list_empty(&sctp_sk(sk)->ep->asocs))
+			asoc = list_entry(sctp_sk(sk)->ep->asocs.next,
+					  sctp_association_t, asocs);
+		return asoc;
+	}
+
+	/* First, verify that this is a kernel address. */
+	if (sctp_is_valid_kaddr((unsigned long) id)) {
+		sctp_association_t *temp = (sctp_association_t *) id;
+
+		/* Verify that this _is_ an sctp_association_t
+		 * data structure and if so, that the socket matches.
+		 */
+		if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) &&
+		    (temp->base.sk == sk))
+			asoc = temp;
+	}
+
+	return asoc;
+}
 
 /* API 3.1.2 bind() - UDP Style Syntax
  * The syntax of bind() is,
@@ -818,19 +852,7 @@
 			}
 		}
 	} else {
-		/* For a peeled-off socket, ignore any associd specified by
-		 * the user with SNDRCVINFO.
-		 */
-		if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sp->type) {
-			if (list_empty(&ep->asocs)) {
-				err = -EINVAL;
-				goto out_unlock;
-			}
-			asoc = list_entry(ep->asocs.next, sctp_association_t,
-					  asocs);
-		} else if (associd) {
-			asoc = sctp_id2assoc(sk, associd);
-		}
+		asoc = sctp_id2assoc(sk, associd);
 		if (!asoc) {
 			err = -EINVAL;
 			goto out_unlock;
@@ -1007,7 +1029,7 @@
 		sctp_set_owner_w(chunk);
 
 		/* This flag, in the UDP model, requests the SCTP stack to
-		 * override the primary destination address with the 
+		 * override the primary destination address with the
 		 * address found with the sendto/sendmsg call.
 		 */
 		if (sinfo_flags & MSG_ADDR_OVER) {
@@ -1126,17 +1148,19 @@
 	int err = 0;
 	int skb_len;
 
-	SCTP_DEBUG_PRINTK("sctp_recvmsg("
-			  "%s: %p, %s: %p, %s: %d, %s: %d, %s: "
-			  "0x%x, %s: %p)\n",
-			  "sk", sk,
-			  "msghdr", msg,
-			  "len", len,
-			  "knoblauch", noblock,
-			  "flags", flags,
-			  "addr_len", addr_len);
+	SCTP_DEBUG_PRINTK("sctp_recvmsg(%s: %p, %s: %p, %s: %d, %s: %d, %s: "
+			  "0x%x, %s: %p)\n", "sk", sk, "msghdr", msg,
+			  "len", len, "knoblauch", noblock,
+			  "flags", flags, "addr_len", addr_len);
 
 	sctp_lock_sock(sk);
+
+	if ((SCTP_SOCKET_TCP == sp->type) &&
+	    (SCTP_SS_ESTABLISHED != sk->state)) {
+		err = -ENOTCONN;
+		goto out;
+	}
+	
 	skb = sctp_skb_recv_datagram(sk, flags, noblock, &err);
 	if (!skb)
 		goto out;
@@ -1207,7 +1231,7 @@
 	return err;
 }
 
-static inline int sctp_setsockopt_disable_fragments(struct sock *sk,
+static int sctp_setsockopt_disable_fragments(struct sock *sk,
 						    char *optval, int optlen)
 {
 	int val;
@@ -1223,8 +1247,8 @@
 	return 0;
 }
 
-static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
-					     int optlen)
+static int sctp_setsockopt_events(struct sock *sk, char *optval,
+					int optlen)
 {
 	if (optlen != sizeof(struct sctp_event_subscribe))
 		return -EINVAL;
@@ -1233,7 +1257,7 @@
 	return 0;
 }
 
-static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
+static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
 					    int optlen)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
@@ -1250,9 +1274,8 @@
 	return 0;
 }
 
-static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
-						       char *optval,
-						       int optlen)
+static int sctp_setsockopt_peer_addr_params(struct sock *sk,
+						   char *optval, int optlen)
 {
 	struct sctp_paddrparams params;
 	sctp_association_t *asoc;
@@ -1290,8 +1313,7 @@
 		error = sctp_primitive_REQUESTHEARTBEAT (asoc, trans);
 		if (error)
 			return error;
-	}
-	else {
+	} else {
 	/* The value of the heartbeat interval, in milliseconds. A value of 0,
 	 * when modifying the parameter, specifies that the heartbeat on this
 	 * address should be disabled.
@@ -1311,7 +1333,7 @@
 	return 0;
 }
 
-static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
+static int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
 					  int optlen)
 {
 	if (optlen != sizeof(struct sctp_initmsg))
@@ -1336,7 +1358,7 @@
  *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
  *   to this call if the caller is using the UDP model.
  */
-static inline int sctp_setsockopt_set_default_send_param(struct sock *sk,
+static int sctp_setsockopt_default_send_param(struct sock *sk,
 						char *optval, int optlen)
 {
 	struct sctp_sndrcvinfo info;
@@ -1359,6 +1381,66 @@
 	return 0;
 }
 
+/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR)
+ *
+ * Requests that the local SCTP stack use the enclosed peer address as
+ * the association primary.  The enclosed address must be one of the
+ * association peer's addresses.
+ */
+static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen)
+{
+	struct sctp_setpeerprim prim;
+	struct sctp_association *asoc;
+	union sctp_addr *addr;
+	struct sctp_transport *trans;
+
+	if (optlen != sizeof(struct sctp_setpeerprim))
+		return -EINVAL;
+
+	if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim)))
+		return -EFAULT;
+
+	asoc = sctp_id2assoc(sk, prim.sspp_assoc_id);
+	if (!asoc)
+		return -EINVAL;
+
+	/* Find the requested address. */
+	addr = (union sctp_addr *) &(prim.sspp_addr);
+
+	trans = sctp_assoc_lookup_paddr(asoc, addr);
+	if (!trans)
+		return -ENOENT;
+
+	sctp_assoc_set_primary(asoc, trans);
+
+	return 0;
+}
+
+/*
+ *
+ * 7.1.5 SCTP_NODELAY
+ *
+ * Turn on/off any Nagle-like algorithm.  This means that packets are
+ * generally sent as soon as possible and no unnecessary delays are
+ * introduced, at the cost of more packets in the network.  Expects an
+ *  integer boolean flag.
+ */
+static int sctp_setsockopt_nodelay(struct sock *sk, char *optval,
+					int optlen)
+{
+	__u8 val;
+
+	if (optlen < sizeof(__u8))
+		return -EINVAL;
+
+	if (get_user(val, (__u8 *)optval))
+		return -EFAULT;
+
+	sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
+
+	return 0;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -1434,7 +1516,7 @@
 		break;
 
 	case SCTP_SET_EVENTS:
-		retval = sctp_setsockopt_set_events(sk, optval, optlen);
+		retval = sctp_setsockopt_events(sk, optval, optlen);
 		break;
 
 	case SCTP_AUTOCLOSE:
@@ -1442,8 +1524,7 @@
 		break;
 
 	case SCTP_SET_PEER_ADDR_PARAMS:
-		retval = sctp_setsockopt_set_peer_addr_params(sk, optval,
-							      optlen);
+		retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
 		break;
 
 	case SCTP_INITMSG:
@@ -1451,8 +1532,16 @@
 		break;
 
 	case SCTP_SET_DEFAULT_SEND_PARAM:
-		retval = sctp_setsockopt_set_default_send_param(sk,
-							optval, optlen);
+		retval = sctp_setsockopt_default_send_param(sk, optval,
+							    optlen);
+		break;
+
+	case SCTP_SET_PEER_PRIMARY_ADDR:
+		retval = sctp_setsockopt_peer_prim(sk, optval, optlen);
+		break;
+
+	case SCTP_NODELAY:
+		retval = sctp_setsockopt_nodelay(sk, optval, optlen);
 		break;
 
 	default:
@@ -1503,8 +1592,14 @@
 	sp = sctp_sk(sk);
 	ep = sp->ep;
 
-	/* connect() cannot be done on a peeled-off socket. */
-	if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sp->type) {
+	/* connect() cannot be done on a socket that is already in ESTABLISHED
+	 * state - UDP-style peeled off socket or a TCP-style socket that
+	 * is already connected. 
+	 * It cannot be done even on a TCP-style listening socket.
+	 */
+	if ((SCTP_SS_ESTABLISHED == sk->state) ||
+	    ((SCTP_SOCKET_TCP == sp->type) &&
+	     (SCTP_SS_LISTENING == sk->state))) {
 		err = -EISCONN;
 		goto out_unlock;
 	}
@@ -1513,6 +1608,8 @@
 	if (err)
 		goto out_unlock;
 
+	if (addr_len > sizeof(to))
+		addr_len = sizeof(to);
 	memcpy(&to, uaddr, addr_len);
 	to.v4.sin_port = ntohs(to.v4.sin_port);
 
@@ -1585,13 +1682,63 @@
 	return -EOPNOTSUPP; /* STUB */
 }
 
-/* FIXME: Write comments. */
+/* 4.1.4 accept() - TCP Style Syntax
+ *
+ * Applications use accept() call to remove an established SCTP
+ * association from the accept queue of the endpoint.  A new socket
+ * descriptor will be returned from accept() to represent the newly
+ * formed association.
+ */
 SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err)
 {
-	int error = -EOPNOTSUPP;
+	struct sctp_opt *sp;
+	struct sctp_endpoint *ep;
+	struct sock *newsk = NULL;
+	struct sctp_association *assoc;
+	long timeo;
+	int error = 0;
+ 
+	sctp_lock_sock(sk);
 
-	*err = error;
-	return NULL;
+	sp = sctp_sk(sk);
+	ep = sp->ep;
+
+	if (SCTP_SOCKET_TCP != sp->type) {
+		error = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (SCTP_SS_LISTENING != sk->state) {
+		error = -EINVAL;
+		goto out;
+	}
+
+	timeo = sock_rcvtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK);
+
+	error = sctp_wait_for_accept(sk, timeo);
+	if (error)
+		goto out;
+
+	/* We treat the list of associations on the endpoint as the accept 
+	 * queue and pick the first association on the list. 
+	 */
+	assoc = list_entry(ep->asocs.next, struct sctp_association, asocs);
+
+	newsk = sp->pf->create_accept_sk(sk, assoc); 
+	if (!newsk) {
+		error = -ENOMEM;
+		goto out;
+	}
+
+	/* Populate the fields of the newsk from the oldsk and migrate the
+	 * assoc to the newsk.
+	 */ 
+	sctp_sock_migrate(sk, newsk, assoc, SCTP_SOCKET_TCP);
+
+out:
+	sctp_release_sock(sk);
+ 	*err = error;
+	return newsk;
 }
 
 /* FIXME: Write Comments. */
@@ -1607,7 +1754,7 @@
 SCTP_STATIC int sctp_init_sock(struct sock *sk)
 {
 	sctp_endpoint_t *ep;
-	sctp_protocol_t *proto;
+	struct sctp_protocol *proto;
 	struct sctp_opt *sp;
 
 	SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk);
@@ -1617,7 +1764,16 @@
 	sp = sctp_sk(sk);
 
 	/* Initialize the SCTP per socket area.  */
-	sp->type = SCTP_SOCKET_UDP;
+	switch (sk->type) {
+	case SOCK_SEQPACKET:
+		sp->type = SCTP_SOCKET_UDP;
+		break;
+	case SOCK_STREAM:
+		sp->type = SCTP_SOCKET_TCP;
+		break;
+	default:
+		return -ESOCKTNOSUPPORT;
+	}
 
 	/* FIXME:  The next draft (04) of the SCTP Sockets Extensions
 	 * should include a socket option for manipulating these
@@ -1665,7 +1821,7 @@
 	sp->disable_fragments = 0;
 
 	/* Turn on/off any Nagle-like algorithm.  */
-	sp->nodelay           = 0;
+	sp->nodelay           = 1;
 
 	/* Auto-close idle associations after the configured
 	 * number of seconds.  A value of 0 disables this
@@ -1714,11 +1870,17 @@
 	/* STUB */
 }
 
+/* 7.2.1 Association Status (SCTP_STATUS)
+
+ * Applications can retrieve current status information about an
+ * association, including association state, peer receiver window size,
+ * number of unacked data chunks, and number of data chunks pending
+ * receipt.  This information is read-only.
+ */
 static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
 				       int *optlen)
 {
 	struct sctp_status status;
-	sctp_endpoint_t *ep;
 	sctp_association_t *assoc = NULL;
 	struct sctp_transport *transport;
 	sctp_assoc_t associd;
@@ -1735,20 +1897,10 @@
 	}
 
 	associd = status.sstat_assoc_id;
-	if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sctp_sk(sk)->type) && associd) {
-		assoc = sctp_id2assoc(sk, associd);
-		if (!assoc) {
-			retval = -EINVAL;
-			goto out;
-		}
-	} else {
-		ep = sctp_sk(sk)->ep;
-		if (list_empty(&ep->asocs)) {
-			retval = -EINVAL;
-			goto out;
-		}
-
-		assoc = list_entry(ep->asocs.next, sctp_association_t, asocs);
+	assoc = sctp_id2assoc(sk, associd);
+	if (!assoc) {
+		retval = -EINVAL;
+		goto out;
 	}
 
 	transport = assoc->peer.primary_path;
@@ -1788,7 +1940,7 @@
 	return (retval);
 }
 
-static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
+static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
 						    char *optval, int *optlen)
 {
 	int val;
@@ -1805,7 +1957,7 @@
 	return 0;
 }
 
-static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen)
+static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen)
 {
 	if (len != sizeof(struct sctp_event_subscribe))
 		return -EINVAL;
@@ -1814,7 +1966,7 @@
 	return 0;
 }
 
-static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
+static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
 {
 	/* Applicable to UDP-style socket only */
 	if (SCTP_SOCKET_TCP == sctp_sk(sk)->type)
@@ -1832,11 +1984,6 @@
 	struct sock *oldsk = assoc->base.sk;
 	struct sock *newsk;
 	struct socket *tmpsock;
-	sctp_endpoint_t *newep;
-	struct sctp_opt *oldsp = sctp_sk(oldsk);
-	struct sctp_opt *newsp;
-	struct sk_buff *skb, *tmp;
-	struct sctp_ulpevent *event;
 	int err = 0;
 
 	/* An association cannot be branched off from an already peeled-off
@@ -1846,88 +1993,24 @@
 		return -EOPNOTSUPP;
 
 	/* Create a new socket.  */
-	err = sock_create(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, &tmpsock);
+	err = sock_create(oldsk->family, SOCK_SEQPACKET, IPPROTO_SCTP,
+			  &tmpsock);
 	if (err < 0)
 		return err;
 
 	newsk = tmpsock->sk;
-	newsp = sctp_sk(newsk);
-	newep = newsp->ep;
-
-	/* Migrate socket buffer sizes and all the socket level options to the
-	 * new socket.
-	 */
-	newsk->sndbuf = oldsk->sndbuf;
-	newsk->rcvbuf = oldsk->rcvbuf;
-	*newsp = *oldsp;
-
-	/* Restore the ep value that was overwritten with the above structure
-	 * copy.
-	 */
-	newsp->ep = newep;
-
-	/* Move any messages in the old socket's receive queue that are for the
-	 * peeled off association to the new socket's receive queue.
-	 */
-	sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) {
-		event = sctp_skb2event(skb);
-		if (event->asoc == assoc) {
-			__skb_unlink(skb, skb->list);
-			__skb_queue_tail(&newsk->receive_queue, skb);
-		}
-	}
 
-	/* Clean up an messages pending delivery due to partial
-	 * delivery.   Three cases:
-	 * 1) No partial deliver;  no work.
-	 * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
-	 * 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
-	 */
-	skb_queue_head_init(&newsp->pd_lobby);
-	sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;;
-
-	if (sctp_sk(oldsk)->pd_mode) {
-		struct sk_buff_head *queue;
-
-		/* Decide which queue to move pd_lobby skbs to. */
-		if (assoc->ulpq.pd_mode) {
-			queue = &newsp->pd_lobby;
-		} else
-			queue = &newsk->receive_queue;
-
-		/* Walk through the pd_lobby, looking for skbs that
-		 * need moved to the new socket.
-		 */
-		sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
-			event = sctp_skb2event(skb);
-			if (event->asoc == assoc) {
-				__skb_unlink(skb, skb->list);
-				__skb_queue_tail(queue, skb);
-			}
-		}
-
-		/* Clear up any skbs waiting for the partial
-		 * delivery to finish.
-		 */
-		if (assoc->ulpq.pd_mode)
-			sctp_clear_pd(oldsk);
-
-	}
-
-	/* Set the type of socket to indicate that it is peeled off from the
-	 * original socket.
-	 */
-	newsp->type = SCTP_SOCKET_UDP_HIGH_BANDWIDTH;
-
-	/* Migrate the association to the new socket.  */
-	sctp_assoc_migrate(assoc, newsk);
+	/* Populate the fields of the newsk from the oldsk and migrate the
+	 * assoc to the newsk.
+	 */ 
+	sctp_sock_migrate(oldsk, newsk, assoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
 
 	*newsock = tmpsock;
 
 	return err;
 }
 
-static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen)
+static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen)
 {
 	sctp_peeloff_arg_t peeloff;
 	struct socket *newsock;
@@ -1970,8 +2053,8 @@
 	return retval;
 }
 
-static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk,
-					int len, char *optval, int *optlen)
+static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, 
+						char *optval, int *optlen)
 {
 	struct sctp_paddrparams params;
 	sctp_association_t *asoc;
@@ -2014,7 +2097,7 @@
 	return 0;
 }
 
-static inline int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen)
+static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen)
 {
 	if (len != sizeof(struct sctp_initmsg))
 		return -EINVAL;
@@ -2023,8 +2106,8 @@
 	return 0;
 }
 
-static inline int sctp_getsockopt_get_peer_addrs_num(struct sock *sk, int len,
-				char *optval, int *optlen)
+static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, 
+					char *optval, int *optlen)
 {
 	sctp_assoc_t id;
 	sctp_association_t *asoc;
@@ -2053,7 +2136,7 @@
 	return 0;
 }
 
-static inline int sctp_getsockopt_get_peer_addrs(struct sock *sk, int len,
+static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
 				char *optval, int *optlen)
 {
 	sctp_association_t *asoc;
@@ -2093,8 +2176,8 @@
 	return 0;
 }
 
-static inline int sctp_getsockopt_get_local_addrs_num(struct sock *sk, int len,
-				char *optval, int *optlen)
+static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
+						char *optval, int *optlen)
 {
 	sctp_assoc_t id;
 	sctp_bind_addr_t *bp;
@@ -2132,8 +2215,8 @@
 	return 0;
 }
 
-static inline int sctp_getsockopt_get_local_addrs(struct sock *sk, int len,
-				char *optval, int *optlen)
+static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
+					char *optval, int *optlen)
 {
 	sctp_bind_addr_t *bp;
 	sctp_association_t *asoc;
@@ -2183,6 +2266,40 @@
 	return 0;
 }
 
+/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR)
+ *
+ * Requests that the local SCTP stack use the enclosed peer address as
+ * the association primary.  The enclosed address must be one of the
+ * association peer's addresses.
+ */
+static int sctp_getsockopt_peer_prim(struct sock *sk, int len,
+				char *optval, int *optlen)
+{
+	struct sctp_setpeerprim prim;
+	struct sctp_association *asoc;
+
+	if (len != sizeof(struct sctp_setpeerprim))
+		return -EINVAL;
+
+	if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim)))
+		return -EFAULT;
+
+	asoc = sctp_id2assoc(sk, prim.sspp_assoc_id);
+	if (!asoc)
+		return -EINVAL;
+
+	if (!asoc->peer.primary_path)
+		return -ENOTCONN;
+
+	memcpy(&prim.sspp_addr, &asoc->peer.primary_path->ipaddr,
+	       sizeof(union sctp_addr));
+
+	if (copy_to_user(optval, &prim, sizeof(struct sctp_setpeerprim)))
+		return -EFAULT;
+
+	return 0;
+}
+
 /*
  *
  * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
@@ -2200,7 +2317,7 @@
  *
  *   For getsockopt, it get the default sctp_sndrcvinfo structure.
  */
-static inline int sctp_getsockopt_set_default_send_param(struct sock *sk,
+static int sctp_getsockopt_default_send_param(struct sock *sk,
 					int len, char *optval, int *optlen)
 {
 	struct sctp_sndrcvinfo info;
@@ -2227,6 +2344,33 @@
 	return 0;
 }
 
+/*
+ *
+ * 7.1.5 SCTP_NODELAY
+ *
+ * Turn on/off any Nagle-like algorithm.  This means that packets are
+ * generally sent as soon as possible and no unnecessary delays are
+ * introduced, at the cost of more packets in the network.  Expects an
+ * integer boolean flag.
+ */
+
+static int sctp_getsockopt_nodelay(struct sock *sk, int len, 
+					char *optval, int *optlen)
+{
+	__u8 val;
+
+	if (len < sizeof(__u8))
+		return -EINVAL;
+
+	len = sizeof(__u8);
+	val = (sctp_sk(sk)->nodelay == 1);
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
+	return 0;
+}
+
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
 				char *optval, int *optlen)
 {
@@ -2257,58 +2401,52 @@
 	case SCTP_STATUS:
 		retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen);
 		break;
-
 	case SCTP_DISABLE_FRAGMENTS:
 		retval = sctp_getsockopt_disable_fragments(sk, len, optval,
 							   optlen);
 		break;
-
 	case SCTP_SET_EVENTS:
 		retval = sctp_getsockopt_set_events(sk, len, optval, optlen);
 		break;
-
 	case SCTP_AUTOCLOSE:
 		retval = sctp_getsockopt_autoclose(sk, len, optval, optlen);
 		break;
-
 	case SCTP_SOCKOPT_PEELOFF:
 		retval = sctp_getsockopt_peeloff(sk, len, optval, optlen);
 		break;
-
 	case SCTP_GET_PEER_ADDR_PARAMS:
-		retval = sctp_getsockopt_get_peer_addr_params(sk, len, optval,
-							      optlen);
+		retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
+							  optlen);
 		break;
-
 	case SCTP_INITMSG:
 		retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
 		break;
-
 	case SCTP_GET_PEER_ADDRS_NUM:
-		retval = sctp_getsockopt_get_peer_addrs_num(sk, len, optval,
-							      optlen);
+		retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, 
+							optlen);
 		break;
-
 	case SCTP_GET_LOCAL_ADDRS_NUM:
-		retval = sctp_getsockopt_get_local_addrs_num(sk, len, optval,
-							      optlen);
+		retval = sctp_getsockopt_local_addrs_num(sk, len, optval,
+							 optlen);
 		break;
-
 	case SCTP_GET_PEER_ADDRS:
-		retval = sctp_getsockopt_get_peer_addrs(sk, len, optval,
-							      optlen);
+		retval = sctp_getsockopt_peer_addrs(sk, len, optval,
+						    optlen);
 		break;
-
 	case SCTP_GET_LOCAL_ADDRS:
-		retval = sctp_getsockopt_get_local_addrs(sk, len, optval,
-							      optlen);
+		retval = sctp_getsockopt_local_addrs(sk, len, optval,
+						     optlen);
 		break;
-
 	case SCTP_SET_DEFAULT_SEND_PARAM:
-		retval = sctp_getsockopt_set_default_send_param(sk, len,
-							optval, optlen);
+		retval = sctp_getsockopt_default_send_param(sk, len,
+							    optval, optlen);
+		break;
+	case SCTP_SET_PEER_PRIMARY_ADDR:
+		retval = sctp_getsockopt_peer_prim(sk, len, optval, optlen);
+		break;
+	case SCTP_NODELAY:
+		retval = sctp_getsockopt_nodelay(sk, len, optval, optlen);
 		break;
-
 	default:
 		retval = -ENOPROTOOPT;
 		break;
@@ -2331,7 +2469,7 @@
 /* Check if port is acceptable.  Possibly find first available port.
  *
  * The port hash table (contained in the 'global' SCTP protocol storage
- * returned by sctp_protocol_t * sctp_get_protocol()). The hash
+ * returned by struct sctp_protocol *sctp_get_protocol()). The hash
  * table is an array of 4096 lists (sctp_bind_hashbucket_t). Each
  * list (the list number is the port number hashed out, so as you
  * would expect from a hash function, all the ports in a given list have
@@ -2346,7 +2484,7 @@
 {
 	sctp_bind_hashbucket_t *head; /* hash list */
 	sctp_bind_bucket_t *pp; /* hash list port iterator */
-	sctp_protocol_t *sctp = sctp_get_protocol();
+	struct sctp_protocol *sctp = sctp_get_protocol();
 	unsigned short snum;
 	int ret;
 
@@ -2543,6 +2681,9 @@
 	if (SCTP_SOCKET_UDP != sp->type)
 		return -EINVAL;
 
+	if (sk->state == SCTP_SS_LISTENING)
+		return 0;
+
 	/*
 	 * If a bind() or sctp_bindx() is not called prior to a listen()
 	 * call that allows new associations to be accepted, the system
@@ -2563,6 +2704,40 @@
 }
 
 /*
+ * 4.1.3 listen() - TCP Style Syntax
+ *
+ *   Applications uses listen() to ready the SCTP endpoint for accepting 
+ *   inbound associations.
+ */
+SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
+{
+	struct sctp_opt *sp = sctp_sk(sk);
+	sctp_endpoint_t *ep = sp->ep;
+
+	if (sk->state == SCTP_SS_LISTENING)
+		return 0;
+
+	/*
+	 * If a bind() or sctp_bindx() is not called prior to a listen()
+	 * call that allows new associations to be accepted, the system
+	 * picks an ephemeral port and will choose an address set equivalent
+	 * to binding with a wildcard address.
+	 *
+	 * This is not currently spelled out in the SCTP sockets
+	 * extensions draft, but follows the practice as seen in TCP
+	 * sockets.
+	 */
+	if (!ep->base.bind_addr.port) {
+		if (sctp_autobind(sk))
+			return -EAGAIN;
+	}
+	sk->state = SCTP_SS_LISTENING;
+	sk->max_ack_backlog = backlog;
+	sctp_hash_endpoint(ep);
+	return 0;
+}
+
+/*
  *  Move a socket to LISTENING state.
  */
 int sctp_inet_listen(struct socket *sock, int backlog)
@@ -2579,10 +2754,9 @@
 	case SOCK_SEQPACKET:
 		err = sctp_seqpacket_listen(sk, backlog);
 		break;
-
 	case SOCK_STREAM:
-		/* FIXME for TCP-style sockets. */
-		err = -EOPNOTSUPP;
+		err = sctp_stream_listen(sk, backlog);
+		break;
 
 	default:
 		goto out;
@@ -2684,7 +2858,7 @@
 /* FIXME: Commments! */
 static __inline__ void __sctp_put_port(struct sock *sk)
 {
-	sctp_protocol_t *sctp_proto = sctp_get_protocol();
+	struct sctp_protocol *sctp_proto = sctp_get_protocol();
 	sctp_bind_hashbucket_t *head =
 		&sctp_proto->port_hashtable[sctp_phashfn(inet_sk(sk)->num)];
 	sctp_bind_bucket_t *pp;
@@ -2967,7 +3141,8 @@
 }
 
 /* Verify that this is a valid address. */
-static int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len)
+static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, 
+				   int len)
 {
 	struct sctp_af *af;
 
@@ -3213,7 +3388,7 @@
 	return err;
 
 do_error:
-	err = -ECONNABORTED;
+	err = -ECONNREFUSED;
 	goto out;
 
 do_interrupted:
@@ -3225,6 +3400,131 @@
 	goto out;
 }
 
+static int sctp_wait_for_accept(struct sock *sk, long timeo)
+{
+	struct sctp_endpoint *ep;
+	int err = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	ep = sctp_sk(sk)->ep;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		if (list_empty(&ep->asocs)) {
+			sctp_release_sock(sk);
+			timeo = schedule_timeout(timeo);
+			sctp_lock_sock(sk);
+		}
+
+		err = -EINVAL;
+		if (sk->state != SCTP_SS_LISTENING)
+			break;
+
+		err = 0;
+		if (!list_empty(&ep->asocs))
+			break;
+
+		err = sock_intr_errno(timeo);
+		if (signal_pending(current))
+			break;
+
+		err = -EAGAIN;
+		if (!timeo)
+			break;
+	}
+
+	remove_wait_queue(sk->sleep, &wait);
+	__set_current_state(TASK_RUNNING);
+
+	return err;
+}
+
+/* Populate the fields of the newsk from the oldsk and migrate the assoc 
+ * and its messages to the newsk.
+ */ 
+void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
+		  struct sctp_association *assoc, sctp_socket_type_t type)
+{
+	struct sctp_opt *oldsp = sctp_sk(oldsk);
+	struct sctp_opt *newsp = sctp_sk(newsk);
+	sctp_endpoint_t *newep = newsp->ep;
+	struct sk_buff *skb, *tmp;
+	struct sctp_ulpevent *event;
+
+	/* Migrate socket buffer sizes and all the socket level options to the
+	 * new socket.
+	 */
+	newsk->sndbuf = oldsk->sndbuf;
+	newsk->rcvbuf = oldsk->rcvbuf;
+	*newsp = *oldsp;
+
+	/* Restore the ep value that was overwritten with the above structure
+	 * copy.
+	 */
+	newsp->ep = newep;
+
+	/* Move any messages in the old socket's receive queue that are for the
+	 * peeled off association to the new socket's receive queue.
+	 */
+	sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) {
+		event = sctp_skb2event(skb);
+		if (event->asoc == assoc) {
+			__skb_unlink(skb, skb->list);
+			__skb_queue_tail(&newsk->receive_queue, skb);
+		}
+	}
+
+	/* Clean up any messages pending delivery due to partial
+	 * delivery.   Three cases:
+	 * 1) No partial deliver;  no work.
+	 * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
+	 * 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
+	 */
+	skb_queue_head_init(&newsp->pd_lobby);
+	sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;;
+
+	if (sctp_sk(oldsk)->pd_mode) {
+		struct sk_buff_head *queue;
+
+		/* Decide which queue to move pd_lobby skbs to. */
+		if (assoc->ulpq.pd_mode) {
+			queue = &newsp->pd_lobby;
+		} else
+			queue = &newsk->receive_queue;
+
+		/* Walk through the pd_lobby, looking for skbs that
+		 * need moved to the new socket.
+		 */
+		sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
+			event = sctp_skb2event(skb);
+			if (event->asoc == assoc) {
+				__skb_unlink(skb, skb->list);
+				__skb_queue_tail(queue, skb);
+			}
+		}
+
+		/* Clear up any skbs waiting for the partial
+		 * delivery to finish.
+		 */
+		if (assoc->ulpq.pd_mode)
+			sctp_clear_pd(oldsk);
+
+	}
+
+	/* Set the type of socket to indicate that it is peeled off from the
+	 * original UDP-style socket or created with the accept() call on a
+	 * TCP-style socket..
+	 */
+	newsp->type = type;
+
+	/* Migrate the association to the new socket. */
+	sctp_assoc_migrate(assoc, newsk);
+
+	newsk->state = SCTP_SS_ESTABLISHED;
+}
+ 
 /* This proto struct describes the ULP interface for SCTP.  */
 struct proto sctp_prot = {
 	.name        =	"SCTP",
diff -urN linux-2.5.65-bk1/net/sctp/sysctl.c linux-2.5.65-bk2/net/sctp/sysctl.c
--- linux-2.5.65-bk1/net/sctp/sysctl.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/net/sctp/sysctl.c	Mon Mar 31 12:39:51 2003
@@ -42,7 +42,7 @@
 #include <net/sctp/structs.h>
 #include <linux/sysctl.h>
 
-extern sctp_protocol_t sctp_proto;
+extern struct sctp_protocol sctp_proto;
 
 static ctl_table sctp_table[] = {
 	{
diff -urN linux-2.5.65-bk1/net/sctp/transport.c linux-2.5.65-bk2/net/sctp/transport.c
--- linux-2.5.65-bk1/net/sctp/transport.c	Mon Mar 17 13:43:45 2003
+++ linux-2.5.65-bk2/net/sctp/transport.c	Mon Mar 31 12:39:51 2003
@@ -83,7 +83,7 @@
 					   const union sctp_addr *addr,
 					   int priority)
 {
-	sctp_protocol_t *proto = sctp_get_protocol();
+	struct sctp_protocol *proto = sctp_get_protocol();
 
 	/* Copy in the address.  */
 	peer->ipaddr = *addr;
@@ -262,7 +262,7 @@
 /* Update transport's RTO based on the newly calculated RTT. */
 void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
 {
-	sctp_protocol_t *proto = sctp_get_protocol();
+	struct sctp_protocol *proto = sctp_get_protocol();
 
 	/* Check for valid transport.  */
 	SCTP_ASSERT(tp, "NULL transport", return);
diff -urN linux-2.5.65-bk1/net/sctp/tsnmap.c linux-2.5.65-bk2/net/sctp/tsnmap.c
--- linux-2.5.65-bk1/net/sctp/tsnmap.c	Mon Mar 17 13:44:48 2003
+++ linux-2.5.65-bk2/net/sctp/tsnmap.c	Mon Mar 31 12:39:51 2003
@@ -250,7 +250,7 @@
 	/* The Gap Ack Block happens to end at the end of the
 	 * overflow map.
 	 */
-	if (started & !ended) {
+	if (started && !ended) {
 		ended++;
 		_end = map->len + map->len - 1;
 	}
@@ -395,7 +395,7 @@
 		return;
 	if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
 		return;
-	
+
 	/* Assert: TSN is in range.  */
 	gap = tsn - map->base_tsn;
 
diff -urN linux-2.5.65-bk1/net/sctp/ulpqueue.c linux-2.5.65-bk2/net/sctp/ulpqueue.c
--- linux-2.5.65-bk1/net/sctp/ulpqueue.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/net/sctp/ulpqueue.c	Mon Mar 31 12:39:51 2003
@@ -220,7 +220,7 @@
 	if (sctp_event2skb(event)->list)
 		sctp_skb_list_tail(sctp_event2skb(event)->list, queue);
 	else
-		skb_queue_tail(queue, sctp_event2skb(event));
+		__skb_queue_tail(queue, sctp_event2skb(event));
 
 	/* Did we just complete partial delivery and need to get
 	 * rolling again?  Move pending data to the receive
@@ -230,7 +230,7 @@
 		sctp_ulpq_clear_pd(ulpq);
 
 	if (queue == &sk->receive_queue)
-		wake_up_interruptible(sk->sleep);
+		sk->data_ready(sk, 0);
 	return 1;
 
 out_free:
@@ -247,14 +247,14 @@
 static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
 					 struct sctp_ulpevent *event)
 {
-	struct sk_buff *pos, *tmp;
+	struct sk_buff *pos;
 	struct sctp_ulpevent *cevent;
 	__u32 tsn, ctsn;
 
 	tsn = event->sndrcvinfo.sinfo_tsn;
 
 	/* Find the right place in this list. We store them by TSN.  */
-	sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
+	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
 		ctsn = cevent->sndrcvinfo.sinfo_tsn;
 
@@ -334,7 +334,7 @@
  */
 static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq)
 {
-	struct sk_buff *pos, *tmp;
+	struct sk_buff *pos;
 	struct sctp_ulpevent *cevent;
 	struct sk_buff *first_frag = NULL;
 	__u32 ctsn, next_tsn;
@@ -355,7 +355,7 @@
 	 * fragment in order. If not, first_frag is reset to NULL and we
 	 * start the next pass when we find another first fragment.
 	 */
-	sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
+	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
 		ctsn = cevent->sndrcvinfo.sinfo_tsn;
 
@@ -374,29 +374,26 @@
 
 		case SCTP_DATA_LAST_FRAG:
 			if (first_frag && (ctsn == next_tsn))
-				retval = sctp_make_reassembled_event(
-						first_frag, pos);
+				goto found;
 			else
 				first_frag = NULL;
 			break;
 		};
 
-		/* We have the reassembled event. There is no need to look
-		 * further.
-		 */
-		if (retval) {
-			retval->msg_flags |= MSG_EOR;
-			break;
-		}
 	}
-
+done:
 	return retval;
+found:
+	retval = sctp_make_reassembled_event(first_frag, pos);
+	if (retval)
+		retval->msg_flags |= MSG_EOR;
+	goto done;
 }
 
 /* Retrieve the next set of fragments of a partial message. */
 static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq)
 {
-	struct sk_buff *pos, *tmp, *last_frag, *first_frag;
+	struct sk_buff *pos, *last_frag, *first_frag;
 	struct sctp_ulpevent *cevent;
 	__u32 ctsn, next_tsn;
 	int is_last;
@@ -415,7 +412,7 @@
 	next_tsn = 0;
 	is_last = 0;
 
-	sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
+	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
 		ctsn = cevent->sndrcvinfo.sinfo_tsn;
 
@@ -448,7 +445,7 @@
 	 */
 done:
 	retval = sctp_make_reassembled_event(first_frag, last_frag);
-	if (is_last)
+	if (retval && is_last)
 		retval->msg_flags |= MSG_EOR;
 
 	return retval;
@@ -490,7 +487,7 @@
 /* Retrieve the first part (sequential fragments) for partial delivery.  */
 static inline struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq)
 {
-	struct sk_buff *pos, *tmp, *last_frag, *first_frag;
+	struct sk_buff *pos, *last_frag, *first_frag;
 	struct sctp_ulpevent *cevent;
 	__u32 ctsn, next_tsn;
 	struct sctp_ulpevent *retval;
@@ -507,7 +504,7 @@
 	retval = NULL;
 	next_tsn = 0;
 
-	sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
+	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
 		ctsn = cevent->sndrcvinfo.sinfo_tsn;
 
@@ -590,7 +587,7 @@
 static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
 					   struct sctp_ulpevent *event)
 {
-	struct sk_buff *pos, *tmp;
+	struct sk_buff *pos;
 	struct sctp_ulpevent *cevent;
 	__u16 sid, csid;
 	__u16 ssn, cssn;
@@ -601,7 +598,7 @@
 	/* Find the right place in this list.  We store them by
 	 * stream ID and then by SSN.
 	 */
-	sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
+	skb_queue_walk(&ulpq->lobby, pos) {
 		cevent = (struct sctp_ulpevent *) pos->cb;
 		csid = cevent->sndrcvinfo.sinfo_stream;
 		cssn = cevent->sndrcvinfo.sinfo_ssn;
@@ -786,9 +783,9 @@
 					      SCTP_PARTIAL_DELIVERY_ABORTED,
 					      priority);
 	if (ev)
-		skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev));
+		__skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev));
 
 	/* If there is data waiting, send it up the socket now. */
 	if (sctp_ulpq_clear_pd(ulpq) || ev)
-		wake_up_interruptible(sk->sleep);
+		sk->data_ready(sk, 0);
 }
diff -urN linux-2.5.65-bk1/net/unix/af_unix.c linux-2.5.65-bk2/net/unix/af_unix.c
--- linux-2.5.65-bk1/net/unix/af_unix.c	Mon Mar 17 13:44:14 2003
+++ linux-2.5.65-bk2/net/unix/af_unix.c	Mon Mar 31 12:39:51 2003
@@ -859,10 +859,9 @@
 {
 	struct unix_sock *u = unix_sk(other);
 	int sched;
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
-	__set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue_exclusive(&u->peer_wait, &wait);
+	prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE);
 
 	sched = (!test_bit(SOCK_DEAD, &other->flags) &&
 		 !(other->shutdown&RCV_SHUTDOWN) &&
@@ -873,8 +872,7 @@
 	if (sched)
 		timeo = schedule_timeout(timeo);
 
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&u->peer_wait, &wait);
+	finish_wait(&u->peer_wait, &wait);
 	return timeo;
 }
 
@@ -1542,14 +1540,12 @@
  
 static long unix_stream_data_wait(unix_socket * sk, long timeo)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
 	unix_state_rlock(sk);
 
-	add_wait_queue(sk->sleep, &wait);
-
 	for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 
 		if (skb_queue_len(&sk->receive_queue) ||
 		    sk->err ||
@@ -1565,8 +1561,7 @@
 		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 	}
 
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(sk->sleep, &wait);
+	finish_wait(sk->sleep, &wait);
 	unix_state_runlock(sk);
 	return timeo;
 }
diff -urN linux-2.5.65-bk1/sound/arm/sa11xx-uda1341.c linux-2.5.65-bk2/sound/arm/sa11xx-uda1341.c
--- linux-2.5.65-bk1/sound/arm/sa11xx-uda1341.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/sound/arm/sa11xx-uda1341.c	Mon Mar 31 12:39:51 2003
@@ -13,9 +13,48 @@
  * 2002-03-29   Tomas Kasparek  basic capture is working (native ALSA)
  * 2002-03-29   Tomas Kasparek  capture is working (OSS emulation)
  * 2002-04-04   Tomas Kasparek  better rates handling (allow non-standard rates)
+ * 2003-02-14   Brian Avery     fixed full duplex mode, other updates
+ * 2003-02-20   Tomas Kasparek  merged updates by Brian (except HAL)
  */
 
-/* $Id: sa11xx-uda1341.c,v 1.7 2003/02/13 19:19:18 perex Exp $ */
+/* $Id: sa11xx-uda1341.c,v 1.8 2003/02/25 12:48:15 perex Exp $ */
+
+/***************************************************************************************************
+*
+* To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai
+* available in the Alsa doc section on the website		
+* 
+* A few notes to make things clearer. The UDA1341 is hooked up to Serial port 4 on the SA1100.
+* We are using  SSP mode to talk to the UDA1341. The UDA1341 bit & wordselect clocks are generated
+* by this UART. Unfortunately, the clock only runs if the transmit buffer has something in it.
+* So, if we are just recording, we feed the transmit DMA stream a bunch of 0x0000 so that the
+* transmit buffer is full and the clock keeps going. The zeroes come from FLUSH_BASE_PHYS which
+* is a mem loc that always decodes to 0's w/ no off chip access.
+*
+* Some alsa terminology:
+*	frame => num_channels * sample_size  e.g stereo 16 bit is 2 * 16 = 32 bytes
+*	period => the least number of bytes that will generate an interrupt e.g. we have a 1024 byte
+*             buffer and 4 periods in the runtime structure this means we'll get an int every 256
+*             bytes or 4 times per buffer.
+*             A number of the sizes are in frames rather than bytes, use frames_to_bytes and
+*             bytes_to_frames to convert.  The easiest way to tell the units is to look at the
+*             type i.e. runtime-> buffer_size is in frames and its type is snd_pcm_uframes_t
+*             
+*	Notes about the pointer fxn:
+*	The pointer fxn needs to return the offset into the dma buffer in frames.
+*	Interrupts must be blocked before calling the dma_get_pos fxn to avoid race with interrupts.
+*
+*	Notes about pause/resume
+*	Implementing this would be complicated so it's skipped.  The problem case is:
+*	A full duplex connection is going, then play is paused. At this point you need to start xmitting
+*	0's to keep the record active which means you cant just freeze the dma and resume it later you'd
+*	need to	save off the dma info, and restore it properly on a resume.  Yeach!
+*
+*	Notes about transfer methods:
+*	The async write calls fail.  I probably need to implement something else to support them?
+* 
+***************************************************************************************************/
+
 
 #include <sound/driver.h>
 #include <linux/module.h>
@@ -53,8 +92,6 @@
 
 #define chip_t sa11xx_uda1341_t
 
-#define SHIFT_16_STEREO         2
-
 typedef enum stream_id_t{
 	PLAYBACK=0,
 	CAPTURE,
@@ -62,32 +99,29 @@
 }stream_id_t;
 
 typedef struct audio_stream {
-	char *id;		/* identification string */
+	char *id;				/* identification string */
+	int  stream_id;			/* numeric identification */	
 	dma_device_t dma_dev;	/* device identifier for DMA */
 	dma_regs_t *dma_regs;	/* points to our DMA registers */
 
-	int active:1;		/* we are using this stream for transfer now */
+	int active:1;			/* we are using this stream for transfer now */
 
 	int sent_periods;       /* # of sent periods from actual DMA buffer */
 	int sent_total;         /* # of sent periods total (just for info & debug) */
 
 	int sync;               /* are we recoding - flag used to do DMA trans. for sync */
+	spinlock_t dma_lock;	/* for locking in DMA operations (see dma-sa1100.c in the kernel) */
         
 	snd_pcm_substream_t *stream;
 }audio_stream_t;
 
-/* I do not want to have substream = NULL when syncing - ALSA does not like it */
-#define SYNC_SUBSTREAM ((void *) -1)
-
 typedef struct snd_card_sa11xx_uda1341 {
 	struct pm_dev *pm_dev;        
 	snd_card_t *card;
 	struct l3_client *uda1341;
 
 	long samplerate;
-
 	audio_stream_t *s[MAX_STREAMS];
-	snd_info_entry_t *proc_entry;
 }sa11xx_uda1341_t;
 
 static struct snd_card_sa11xx_uda1341 *sa11xx_uda1341 = NULL;
@@ -217,7 +251,9 @@
 		break;
 	}
 
+	/* FMT setting should be moved away when other FMTs are added (FIXME) */
 	l3_command(sa11xx_uda1341->uda1341, CMD_FORMAT, (void *)LSB16);
+	
 	l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk);        
 	Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
 	DEBUG(KERN_DEBUG "set_samplerate done (new rate: %ld)\n", rate);
@@ -237,11 +273,13 @@
 	/* Setup DMA stuff */
 	if (sa11xx_uda1341->s[PLAYBACK]) {
 		sa11xx_uda1341->s[PLAYBACK]->id = "UDA1341 out";
+		sa11xx_uda1341->s[PLAYBACK]->stream_id = PLAYBACK;
 		sa11xx_uda1341->s[PLAYBACK]->dma_dev = DMA_Ser4SSPWr;
 	}
 
 	if (sa11xx_uda1341->s[CAPTURE]) {
 		sa11xx_uda1341->s[CAPTURE]->id = "UDA1341 in";
+		sa11xx_uda1341->s[CAPTURE]->stream_id = CAPTURE;
 		sa11xx_uda1341->s[CAPTURE]->dma_dev = DMA_Ser4SSPRd;
 	}
 
@@ -255,22 +293,24 @@
 	Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);
 	Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
 	Ser4SSCR0 |= SSCR0_SSE;
+	local_irq_restore(flags);
 
 	/* Enable the audio power */
 	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
 	set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
 	set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-	local_irq_restore(flags);
         
 	/* Initialize the UDA1341 internal state */
 	l3_open(sa11xx_uda1341->uda1341);
-
-	/* external clock configuration */
-	sa11xx_uda1341_set_samplerate(sa11xx_uda1341, 44100); /* default sample rate */                
+	
+	/* external clock configuration (after l3_open - regs must be
+	 * initialized */
+	sa11xx_uda1341_set_samplerate(sa11xx_uda1341, AUDIO_RATE_DEFAULT);
 
 	/* Wait for the UDA1341 to wake up */
 	set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
 	mdelay(1);
+	
 
 	/* make the left and right channels unswapped (flip the WS latch ) */
 	Ser4SSDR = 0;
@@ -280,11 +320,16 @@
 
 static void sa11xx_uda1341_audio_shutdown(sa11xx_uda1341_t *sa11xx_uda1341)
 {
+	/* mute on */
+	set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
+	
 	/* disable the audio power and all signals leading to the audio chip */
 	l3_close(sa11xx_uda1341->uda1341);
 	Ser4SSCR0 = 0;
 	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
+	/* power off */
 	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
+	/* mute off */
 	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
 }
 
@@ -292,26 +337,29 @@
 
 /* {{{ DMA staff */
 
-#define SYNC_ADDR		(dma_addr_t)FLUSH_BASE_PHYS
-#define SYNC_SIZE		4096 // was 2048
-
-#define DMA_REQUEST(s, cb)	sa1100_request_dma((s)->dma_dev, (s)->id, cb, s, \
-                                                   &((s)->dma_regs))
-#define DMA_FREE(s)		{sa1100_free_dma((s)->dma_regs); (s)->dma_regs = 0;}
-#define DMA_START(s, d, l)	sa1100_start_dma((s)->dma_regs, d, l)
-#define DMA_STOP(s)		sa1100_stop_dma((s)->dma_regs)
-#define DMA_CLEAR(s)		sa1100_clear_dma((s)->dma_regs)
-#define DMA_RESET(s)		sa1100_reset_dma((s)->dma_regs)
-#define DMA_POS(s)              sa1100_get_dma_pos((s)->dma_regs)
+/*
+ * these are the address and sizes used to fill the xmit buffer
+ * so we can get a clock in record only mode
+ */
+#define FORCE_CLOCK_ADDR		(dma_addr_t)FLUSH_BASE_PHYS
+#define FORCE_CLOCK_SIZE		4096 // was 2048
 
 static void audio_dma_request(audio_stream_t *s, void (*callback)(void *))
 {
-	DMA_REQUEST(s, callback);
+	int ret;
+
+	DEBUG_NAME(KERN_DEBUG "audio_dma_request");
+
+	DEBUG("\t request id <%s>\n", s->id);
+	DEBUG("\t  request dma_dev = 0x%x \n", s->dma_dev);
+	ret = sa1100_request_dma((s)->dma_dev, (s)->id, callback, s, &((s)->dma_regs));
+	DEBUG("\t  request ret = %d\n", ret);
 }
 
 static void audio_dma_free(audio_stream_t *s)
 {
-	DMA_FREE(s);
+	sa1100_free_dma((s)->dma_regs);
+	(s)->dma_regs = 0;
 }
 
 static u_int audio_get_dma_pos(audio_stream_t *s)
@@ -319,12 +367,17 @@
 	snd_pcm_substream_t * substream = s->stream;
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	unsigned int offset;
-        
+	unsigned long flags;
+	
 	DEBUG_NAME(KERN_DEBUG "get_dma_pos");
         
-	offset = DMA_POS(s) - substream->runtime->dma_addr;
+	// this must be called w/ interrupts locked out see dma-sa1100.c in the kernel
+	spin_lock_irqsave(&s->dma_lock, flags);
+	offset = sa1100_get_dma_pos((s)->dma_regs) - runtime->dma_addr;
+	spin_unlock_irqrestore(&s->dma_lock, flags);
+	
 	DEBUG(" %d ->", offset);
-	offset >>= SHIFT_16_STEREO;                
+	offset = bytes_to_frames(runtime,offset);
 	DEBUG(" %d [fr]\n", offset);
         
 	if (offset >= runtime->buffer_size){
@@ -339,27 +392,33 @@
 	return offset;
 }
 
-
+/*
+ * this stops the dma and clears the dma ptrs
+ */
 static void audio_stop_dma(audio_stream_t *s)
 {
 	long flags;
 
 	DEBUG_NAME(KERN_DEBUG "stop_dma\n");
         
-	if (!s->stream)
+	/*
+	 * zero filling streams (sync=1) don;t have alsa streams attached 
+	 * but the 0 fill dma xfer still needs to be stopped
+	 */
+	if (!(s->stream || s->sync))
 		return;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&(s->dma_lock), flags);	
 	s->active = 0;
 	s->sent_periods = 0;
-	s->sent_total = 0;        
+	s->sent_total = 0;
+	s->sync = 0;
 
-	DMA_STOP(s);
-	DMA_CLEAR(s);
-	local_irq_restore(flags);
+	/* this stops the dma channel and clears the buffer ptrs */
+	sa1100_clear_dma((s)->dma_regs);	
+	spin_unlock_irqrestore(&(s->dma_lock), flags);
 }
 
-
 static void audio_reset(audio_stream_t *s)
 {
 	DEBUG_NAME(KERN_DEBUG "dma_reset\n");
@@ -375,40 +434,58 @@
 {
 	snd_pcm_substream_t * substream = s->stream;
 	snd_pcm_runtime_t *runtime;
-	int ret,i;
+	int ret;
                 
 	DEBUG_NAME(KERN_DEBUG "process_dma\n");
 
-	if(!s->active){
-		DEBUG("!!!want to process DMA when stopped!!!\n");
-		return;
-	}
-
 	/* we are requested to process synchronization DMA transfer */
-	if (s->sync) {
+	if(!s->active && s->sync){
+		snd_assert(s->stream_id == PLAYBACK,return);		
+		/* fill the xmit dma buffers and return */
 		while (1) {
-			DEBUG(KERN_DEBUG "sent sync period (dma_size[B]: %d)\n", SYNC_SIZE);
-			ret = DMA_START(s, SYNC_ADDR, SYNC_SIZE);
+			DEBUG(KERN_DEBUG "sent zero dma period (dma_size[B]: %d)\n", FORCE_CLOCK_SIZE);
+			ret = sa1100_start_dma((s)->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);			
 			if (ret)
 				return;   
 		}
 	}
 
-	/* must be set here - for sync there is no runtime struct */
+	/* must be set here - only valid for running streams, not for forced_clock dma fills  */
 	runtime = substream->runtime;
-        
-	while(1) {       
-		unsigned int  dma_size = runtime->period_size << SHIFT_16_STEREO;
-		unsigned int offset = dma_size * s->sent_periods;
                 
+	DEBUG("audio_process_dma hw_ptr_base = 0x%x w_ptr_interrupt = 0x%x "
+		  "period_size = %d  periods  = %d buffer_size = %d sync=0x%x  dma_area = 0x%x\n",
+	       runtime->hw_ptr_base,
+	       runtime->hw_ptr_interrupt,
+	       runtime->period_size,
+	       runtime->periods,
+	       runtime->buffer_size,
+	       runtime->sync,
+	       runtime->dma_area);
+
+	DEBUG("audio_process_dma sent_total = %d  sent_period = %d\n",
+	       s->sent_total,
+	       s->sent_periods);
+	
+	while(s->active) {       
+		unsigned int  dma_size;		
+		unsigned int offset ;
+   
+		dma_size = frames_to_bytes(runtime,runtime->period_size) ;
+		offset = dma_size * s->sent_periods;
 		if (dma_size > MAX_DMA_SIZE){
 			/* this should not happen! */
-			DEBUG(KERN_DEBUG "-----> cut dma_size: %d -> ", dma_size);
+			printk(KERN_ERR "---> cut dma_size: %d -> ", dma_size);
 			dma_size = CUT_DMA_SIZE;
-			DEBUG("%d <-----\n", dma_size);
+			printk("%d <---\n", dma_size);
 		}
 
-		ret = DMA_START(s, runtime->dma_addr + offset, dma_size);
+		/*
+		 * the first time this while loop will run 3 times, i.e. it'll fill the 2 dma
+		 * buffers then get a -EBUSY, every other time it'll refill the completed buffer
+		 * and then get the -EBUSY so it'll just run twice
+		 */
+		ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size);
 		if (ret)
 			return;
 
@@ -429,7 +506,6 @@
 	}
 }
 
-
 static void audio_dma_callback(void *data)
 {
 	audio_stream_t *s = data;
@@ -438,24 +514,26 @@
         
 	DEBUG_NAME(KERN_DEBUG "dma_callback\n");
 
-	/* when syncing we do not have any real stream from ALSA! */
-	if (!s->sync) {
-		snd_pcm_period_elapsed(s->stream);
-		DEBUG(KERN_DEBUG "----> period done <----\n");
+	DEBUG(KERN_DEBUG "----> period done <----\n");
+
 #ifdef DEBUG_MODE
-		printk(KERN_DEBUG "  dma_area:");
-		buf = (char *)s->stream->runtime->dma_addr +
-			((s->sent_periods - 1 ) *
-			 (s->stream->runtime->period_size << SHIFT_16_STEREO));
-		for (i=0; i < 32; i++) {
-			printk(" %02x", *(char *)(buf + i));
-		}
-		printk("\n");
-#endif                      
+	printk(KERN_DEBUG "  dma_area:");
+	buf = (char *)s->stream->runtime->dma_addr + ((s->sent_periods - 1 ) *
+ 		  frames_to_bytes( s->stream->runtime, s->stream->runtime->period_size));	
+	for (i=0; i < 32; i++) {
+		printk(" %02x", *(char *)(buf + i));
 	}
+	printk("\n");
+#endif                      
         
-	if (s->active)
-		audio_process_dma(s);
+   /* 
+	* If we are getting a callback for an active stream then we inform
+	* the PCM middle layer we've finished a period
+	*/
+ 	if (s->active)
+		snd_pcm_period_elapsed(s->stream);
+
+	audio_process_dma(s);
 }
 
 /* }}} */
@@ -491,18 +569,21 @@
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		/* want to capture and have no playback - run DMA syncing */
+		/* now we need to make sure a record only stream has a clock */
 		if (stream_id == CAPTURE && !chip->s[PLAYBACK]->active) {
-			/* we need synchronization DMA transfer (zeros) */
-			DEBUG(KERN_DEBUG "starting synchronization DMA transfer\n");
+			/* we need to force fill the xmit DMA  with zeros */
+			DEBUG(KERN_DEBUG "starting zero fill  DMA transfer\n");
 			chip->s[PLAYBACK]->sync = 1;
-			chip->s[PLAYBACK]->active = 1;
-			chip->s[PLAYBACK]->stream = SYNC_SUBSTREAM; /* not really used! */
 			audio_process_dma(chip->s[PLAYBACK]);
 		}
-		/* want to playback and have capture - stop syncing */
-		if(stream_id == PLAYBACK && chip->s[PLAYBACK]->sync) {
-			chip->s[PLAYBACK]->sync = 0;
+		/* this case is when you were recording then you turn on a
+		 * playback stream so we
+		 * stop (also clears it) the dma first, clear the sync flag
+		 * and then we let it get turned on
+		 */		
+		else if (stream_id == PLAYBACK && chip->s[PLAYBACK]->sync) {
+ 			chip->s[PLAYBACK]->sync = 0;
+			audio_stop_dma(chip->s[PLAYBACK]);
 		}
 
 		/* requested stream startup */
@@ -512,27 +593,30 @@
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		/* want to stop capture and use syncing - stop DMA syncing */
-		if (stream_id == CAPTURE && chip->s[PLAYBACK]->sync) {
-			/* we do not need synchronization DMA transfer now */
-			DEBUG(KERN_DEBUG "stopping synchronization DMA transfer\n");
-			chip->s[PLAYBACK]->sync = 0;
-			chip->s[PLAYBACK]->active = 0;
-			audio_stop_dma(chip->s[PLAYBACK]);
-		}
-		/* want to stop playback and have capture - run DMA syncing */
-		if(stream_id == PLAYBACK && chip->s[CAPTURE]->active) {
-			/* we need synchronization DMA transfer (zeros) */
-			DEBUG(KERN_DEBUG "starting synchronization DMA transfer\n");
-			chip->s[PLAYBACK]->sync = 1;
-			chip->s[PLAYBACK]->active = 1;
-			chip->s[PLAYBACK]->stream = SYNC_SUBSTREAM; /* not really used! */
-			audio_process_dma(chip->s[PLAYBACK]);
-		}
-
 		/* requested stream shutdown */
 		chip->s[stream_id]->active = 0;
 		audio_stop_dma(chip->s[stream_id]);
+		
+		/*
+		 * now we need to make sure a record only stream has a clock
+		 * so if we're stopping a playback with an active capture
+		 * we need to turn the 0 fill dma on for the xmit side
+		 */
+		if (stream_id == PLAYBACK && chip->s[CAPTURE]->active) {
+			/* we need to force fill the xmit DMA  with zeros */
+			DEBUG(KERN_DEBUG "starting zero fill  DMA transfer\n");
+			chip->s[PLAYBACK]->sync = 1;
+			chip->s[PLAYBACK]->active = 0;
+			audio_process_dma(chip->s[PLAYBACK]);
+		}
+		/*
+		 * we killed a capture only stream, so we should also kill
+		 * the zero fill transmit
+		 */
+		else if (stream_id == CAPTURE  && chip->s[PLAYBACK]->sync) {
+			audio_stop_dma(chip->s[PLAYBACK]);
+		}
+		
 		break;
 	default:
 		return -EINVAL;
@@ -601,7 +685,11 @@
 	chip->s[PLAYBACK]->sent_periods = 0;
 	chip->s[PLAYBACK]->sent_total = 0;
         
-	audio_reset(chip->s[PLAYBACK]);
+	/* no reset here since we may be zero filling the DMA
+	 * if we are, the dma stream will get reset in the pcm_trigger
+	 * i.e. when it actually starts to play
+	 */
+	/* audio_reset(chip->s[PLAYBACK]); */
  
 	runtime->hw = snd_sa11xx_uda1341_playback;
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
@@ -652,10 +740,13 @@
 
 static snd_pcm_uframes_t snd_card_sa11xx_uda1341_playback_pointer(snd_pcm_substream_t * substream)
 {
+	snd_pcm_uframes_t pos;
 	sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream);
 
 	DEBUG_NAME(KERN_DEBUG "playback_pointer\n");        
-	return audio_get_dma_pos(chip->s[PLAYBACK]);
+	
+	pos = audio_get_dma_pos(chip->s[PLAYBACK]);
+	return pos;
 }
 
 /* }}} */
@@ -674,7 +765,7 @@
 	chip->s[CAPTURE]->sent_periods = 0;
 	chip->s[CAPTURE]->sent_total = 0;
         
-	audio_reset(chip->s[PLAYBACK]);        
+	audio_reset(chip->s[CAPTURE]);        
 
 	runtime->hw = snd_sa11xx_uda1341_capture;
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
@@ -725,10 +816,12 @@
 
 static snd_pcm_uframes_t snd_card_sa11xx_uda1341_capture_pointer(snd_pcm_substream_t * substream)
 {
+	snd_pcm_uframes_t pos;
 	sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream);
 
 	DEBUG_NAME(KERN_DEBUG "record_pointer\n");        
-	return audio_get_dma_pos(chip->s[CAPTURE]);
+	pos = audio_get_dma_pos(chip->s[CAPTURE]);
+	return pos;
 }
 
 /* }}} */
@@ -784,6 +877,13 @@
 			       substreams, substreams, &pcm)) < 0)
 		return err;
 
+	/*
+	 * this sets up our initial buffers and sets the dma_type to isa.
+	 * isa works but I'm not sure why (or if) it's the right choice
+	 * this may be too large, trying it for now
+	 */
+	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 64*1024);
+
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
 	pcm->private_data = sa11xx_uda1341;
@@ -816,6 +916,10 @@
 
 	DEBUG_NAME(KERN_DEBUG "pm_callback\n");
 
+	/* pause resume is broken  see note */
+	printk("Pause/Resume support currently broken... \n");	
+        return -1;
+
 	is = sa11xx_uda1341->s[PLAYBACK];
 	os = sa11xx_uda1341->s[CAPTURE];
         
diff -urN linux-2.5.65-bk1/sound/core/Makefile linux-2.5.65-bk2/sound/core/Makefile
--- linux-2.5.65-bk1/sound/core/Makefile	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/sound/core/Makefile	Mon Mar 31 12:39:51 2003
@@ -14,8 +14,10 @@
 
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
 		pcm_memory.o
+
+snd-page-alloc-objs := memalloc.o
 ifeq ($(CONFIG_PCI),y)
-snd-pcm-objs += pcm_sgbuf.o
+snd-page-alloc-objs += sgbuf.o memory_wrapper.o
 endif
 
 snd-rawmidi-objs  := rawmidi.o
@@ -31,72 +33,72 @@
 obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
 
 obj-$(CONFIG_SND_MIXER_OSS) += oss/
-obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o oss/
+obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o snd-page-alloc.o oss/
 obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o seq/
 obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd.o
+obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
 obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-rawmidi.o snd.o snd-timer.o
 obj-$(CONFIG_SND_MTPAV) += snd-rawmidi.o snd.o snd-timer.o
 obj-$(CONFIG_SND_MPU401) += snd-rawmidi.o snd.o snd-timer.o
-obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_AD1816A) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_AD1848) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_CS4232) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CS4236) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES1688) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_GUSCLASSIC) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_GUSMAX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_GUSEXTREME) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_INTERWAVE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_INTERWAVE_STB) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o
-obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-pcm.o
-obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd.o
+obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_AD1816A) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_CS4232) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_CS4236) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ES1688) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_GUSCLASSIC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_GUSMAX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_GUSEXTREME) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_INTERWAVE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_INTERWAVE_STB) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o snd-rawmidi.o
+obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-page-alloc.o snd-pcm.o
+obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
 ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-hwdep.o
   obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o
 endif
-obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
 
 obj-m := $(sort $(obj-m))
diff -urN linux-2.5.65-bk1/sound/core/control.c linux-2.5.65-bk2/sound/core/control.c
--- linux-2.5.65-bk1/sound/core/control.c	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/sound/core/control.c	Mon Mar 31 12:39:51 2003
@@ -714,14 +714,14 @@
 			return -EFAULT;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		err = -ENOPROTOOPT;
 #ifdef CONFIG_PM
 		if (card->set_power_state) {
 		    snd_power_lock(card);
 		    err = card->set_power_state(card, err);
 		    snd_power_unlock(card);
-		}
+		} else
 #endif
+			err = -ENOPROTOOPT;
 		return err;
 	case SNDRV_CTL_IOCTL_POWER_STATE:
 #ifdef CONFIG_PM
diff -urN linux-2.5.65-bk1/sound/core/hwdep.c linux-2.5.65-bk2/sound/core/hwdep.c
--- linux-2.5.65-bk1/sound/core/hwdep.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/sound/core/hwdep.c	Mon Mar 31 12:39:51 2003
@@ -107,7 +107,12 @@
 #endif
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&hw->open_wait, &wait);
+	down(&hw->open_mutex);
 	while (1) {
+		if (hw->exclusive && hw->used > 0) {
+			err = -EBUSY;
+			break;
+		}
 		err = hw->ops.open(hw, file);
 		if (err >= 0)
 			break;
@@ -127,20 +132,26 @@
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&hw->open_wait, &wait);
-	if (err >= 0)
+	if (err >= 0) {
 		file->private_data = hw;
+		hw->used++;
+	}
+	up(&hw->open_mutex);
 	return err;
 }
 
 static int snd_hwdep_release(struct inode *inode, struct file * file)
 {
-	int err;
+	int err = -ENXIO;
 	snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO);
+	down(&hw->open_mutex);
 	if (hw->ops.release) {
 		err = hw->ops.release(hw, file);
 		wake_up(&hw->open_wait);
-		return err;
 	}
+	if (hw->used > 0)
+		hw->used--;
+	up(&hw->open_mutex);
 	return -ENXIO;	
 }
 
@@ -166,14 +177,58 @@
 	return 0;
 }
 
+static int snd_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *_info)
+{
+	snd_hwdep_dsp_status_t info;
+	int err;
+	
+	if (! hw->ops.dsp_status)
+		return -ENXIO;
+	memset(&info, 0, sizeof(info));
+	info.dsp_loaded = hw->dsp_loaded;
+	if ((err = hw->ops.dsp_status(hw, &info)) < 0)
+		return err;
+	if (copy_to_user(_info, &info, sizeof(info)))
+		return -EFAULT;
+	return 0;
+}
+
+static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *_info)
+{
+	snd_hwdep_dsp_image_t info;
+	int err;
+	
+	if (! hw->ops.dsp_load || ! hw->ops.dsp_status)
+		return -ENXIO;
+	memset(&info, 0, sizeof(info));
+	if (copy_from_user(&info, _info, sizeof(info)))
+		return -EFAULT;
+	/* check whether the dsp was already loaded */
+	if (hw->dsp_loaded & (1 << info.index))
+		return -EBUSY;
+	if (verify_area(VERIFY_READ, info.image, info.length))
+		return -EFAULT;
+	err = hw->ops.dsp_load(hw, &info);
+	if (err < 0)
+		return err;
+	hw->dsp_loaded |= (1 << info.index);
+	return 0;
+}
+
 static int snd_hwdep_ioctl(struct inode *inode, struct file * file,
 			   unsigned int cmd, unsigned long arg)
 {
 	snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO);
-	if (cmd == SNDRV_HWDEP_IOCTL_PVERSION)
+	switch (cmd) {
+	case SNDRV_HWDEP_IOCTL_PVERSION:
 		return put_user(SNDRV_HWDEP_VERSION, (int *)arg);
-	if (cmd == SNDRV_HWDEP_IOCTL_INFO)
+	case SNDRV_HWDEP_IOCTL_INFO:
 		return snd_hwdep_info(hw, (snd_hwdep_info_t *)arg);
+	case SNDRV_HWDEP_IOCTL_DSP_STATUS:
+		return snd_hwdep_dsp_status(hw, (snd_hwdep_dsp_status_t *)arg);
+	case SNDRV_HWDEP_IOCTL_DSP_LOAD:
+		return snd_hwdep_dsp_load(hw, (snd_hwdep_dsp_image_t *)arg);
+	}
 	if (hw->ops.ioctl)
 		return hw->ops.ioctl(hw, file, cmd, arg);
 	return -ENOTTY;
@@ -298,6 +353,7 @@
 		return err;
 	}
 	init_waitqueue_head(&hwdep->open_wait);
+	init_MUTEX(&hwdep->open_mutex);
 	*rhwdep = hwdep;
 	return 0;
 }
diff -urN linux-2.5.65-bk1/sound/core/info.c linux-2.5.65-bk2/sound/core/info.c
--- linux-2.5.65-bk1/sound/core/info.c	Mon Mar 17 13:44:46 2003
+++ linux-2.5.65-bk2/sound/core/info.c	Mon Mar 31 12:39:51 2003
@@ -220,7 +220,7 @@
 		buf = data->rbuffer;
 		if (buf == NULL)
 			return -EIO;
-		if (file->f_pos >= buf->size)
+		if (file->f_pos >= (long)buf->size)
 			return 0;
 		size = buf->size < count ? buf->size : count;
 		size1 = buf->size - file->f_pos;
@@ -260,7 +260,7 @@
 			return -EIO;
 		if (file->f_pos < 0)
 			return -EINVAL;
-		if (file->f_pos >= buf->len)
+		if (file->f_pos >= (long)buf->len)
 			return -ENOMEM;
 		size = buf->len < count ? buf->len : count;
 		size1 = buf->len - file->f_pos;
@@ -268,7 +268,7 @@
 			size = size1;
 		if (copy_from_user(buf->buffer + file->f_pos, buffer, size))
 			return -EFAULT;
-		if (buf->size < file->f_pos + size)
+		if ((long)buf->size < file->f_pos + size)
 			buf->size = file->f_pos + size;
 		file->f_pos += size;
 		break;
diff -urN linux-2.5.65-bk1/sound/core/init.c linux-2.5.65-bk2/sound/core/init.c
--- linux-2.5.65-bk1/sound/core/init.c	Mon Mar 17 13:43:44 2003
+++ linux-2.5.65-bk2/sound/core/init.c	Mon Mar 31 12:39:51 2003
@@ -495,6 +495,22 @@
 
 #endif
 
+#ifdef MODULE
+static snd_info_entry_t *snd_card_module_info_entry;
+static void snd_card_module_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	int idx;
+	snd_card_t *card;
+
+	for (idx = 0; idx < SNDRV_CARDS; idx++) {
+		read_lock(&snd_card_rwlock);
+		if ((card = snd_cards[idx]) != NULL)
+			snd_iprintf(buffer, "%i %s\n", idx, card->module->name);
+		read_unlock(&snd_card_rwlock);
+	}
+}
+#endif
+
 int __init snd_card_info_init(void)
 {
 	snd_info_entry_t *entry;
@@ -509,6 +525,20 @@
 		return -ENOMEM;
 	}
 	snd_card_info_entry = entry;
+
+#ifdef MODULE
+	entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
+	if (entry) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->c.text.read_size = PAGE_SIZE;
+		entry->c.text.read = snd_card_module_info_read;
+		if (snd_info_register(entry) < 0)
+			snd_info_free_entry(entry);
+		else
+			snd_card_module_info_entry = entry;
+	}
+#endif
+
 	return 0;
 }
 
@@ -516,6 +546,10 @@
 {
 	if (snd_card_info_entry)
 		snd_info_unregister(snd_card_info_entry);
+#ifdef MODULE
+	if (snd_card_module_info_entry)
+		snd_info_unregister(snd_card_module_info_entry);
+#endif
 	return 0;
 }
 
diff -urN linux-2.5.65-bk1/sound/core/ioctl32/hwdep32.c linux-2.5.65-bk2/sound/core/ioctl32/hwdep32.c
--- linux-2.5.65-bk1/sound/core/ioctl32/hwdep32.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/sound/core/ioctl32/hwdep32.c	Mon Mar 31 12:39:51 2003
@@ -20,13 +20,54 @@
 
 #include <sound/driver.h>
 #include <linux/time.h>
+#include <linux/fs.h>
 #include <sound/core.h>
-#include <sound/timer.h>
+#include <sound/hwdep.h>
 #include <asm/uaccess.h>
 #include "ioctl32.h"
 
+struct sndrv_hwdep_dsp_image32 {
+	u32 index;
+	unsigned char name[64];
+	u32 image;	/* pointer */
+	u32 length;
+	u32 driver_data;
+} /* don't set packed attribute here */;
+
+static int _snd_ioctl32_hwdep_dsp_image(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
+{
+	struct sndrv_hwdep_dsp_image data;
+	struct sndrv_hwdep_dsp_image data32;
+	mm_segment_t oldseg;
+	int err;
+
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+		return -EFAULT;
+	memset(&data, 0, sizeof(data));
+	data.index = data32.index;
+	memcpy(data.name, data32.name, sizeof(data.name));
+	data.image = A(data32.image);
+	data.length = data32.length;
+	data.driver_data = data32.driver_data;
+	oldseg = get_fs();
+	set_fs(KERNEL_DS);
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	set_fs(oldseg);
+	return err;
+}
+
+DEFINE_ALSA_IOCTL_ENTRY(hwdep_dsp_image, hwdep_dsp_image, SNDRV_HWDEP_IOCTL_DSP_LOAD);
+
+#define AP(x) snd_ioctl32_##x
+
+enum {
+	SNDRV_HWDEP_IOCTL_DSP_LOAD32   = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
+};
+
 struct ioctl32_mapper hwdep_mappers[] = {
-	{ SNDRV_HWDEP_IOCTL_PVERSION, NULL },
-	{ SNDRV_HWDEP_IOCTL_INFO, NULL },
+	MAP_COMPAT(SNDRV_HWDEP_IOCTL_PVERSION),
+	MAP_COMPAT(SNDRV_HWDEP_IOCTL_INFO),
+	MAP_COMPAT(SNDRV_HWDEP_IOCTL_DSP_STATUS),
+	{ SNDRV_HWDEP_IOCTL_DSP_LOAD32, AP(hwdep_dsp_image) },
 	{ 0 },
 };
diff -urN linux-2.5.65-bk1/sound/core/isadma.c linux-2.5.65-bk2/sound/core/isadma.c
--- linux-2.5.65-bk1/sound/core/isadma.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/sound/core/isadma.c	Mon Mar 31 12:39:51 2003
@@ -96,5 +96,8 @@
 	if (result > size)
 		snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
 #endif
-	return result >= size ? 0 : size - result;
+	if (result >= size || result == 0)
+		return 0;
+	else
+		return size - result;
 }
diff -urN linux-2.5.65-bk1/sound/core/memalloc.c linux-2.5.65-bk2/sound/core/memalloc.c
--- linux-2.5.65-bk1/sound/core/memalloc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/sound/core/memalloc.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,785 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *                   Takashi Iwai <tiwai@suse.de>
+ * 
+ *  Generic memory allocators
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <sound/memalloc.h>
+
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("Memory allocator for ALSA system.");
+MODULE_LICENSE("GPL");
+
+
+/*
+ */
+
+static DECLARE_MUTEX(list_mutex);
+static LIST_HEAD(mem_list_head);
+
+/* buffer preservation list */
+struct snd_mem_list {
+	struct snd_dma_device dev;
+	struct snd_dma_buffer buffer;
+	int used;
+	struct list_head list;
+};
+
+
+#ifdef CONFIG_SND_DEBUG
+#define __ASTRING__(x) #x
+#define snd_assert(expr, args...) do {\
+	if (!(expr)) {\
+		printk(KERN_ERR "snd-malloc: BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
+		args;\
+	}\
+} while (0)
+#else
+#define snd_assert(expr, args...) /**/
+#endif
+
+/* redefine pci_alloc_consistent for some architectures */
+#ifdef HACK_PCI_ALLOC_CONSISTENT
+#undef pci_alloc_consistent
+#define pci_alloc_consistent snd_pci_hack_alloc_consistent
+#endif
+
+
+/*
+ * compare the two devices
+ * returns non-zero if matched.
+ */
+static int compare_device(const struct snd_dma_device *a, const struct snd_dma_device *b)
+{
+	if (a->type != b->type)
+		return 0;
+	if (a->id != b->id)
+		return 0;
+	switch (a->type) {
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+#ifdef CONFIG_ISA
+	case SNDRV_DMA_TYPE_ISA:
+#endif
+		return a->dev.flags == b->dev.flags;
+#ifdef CONFIG_PCI
+	case SNDRV_DMA_TYPE_PCI:
+		return a->dev.pci == b->dev.pci;
+#endif
+#ifdef CONFIG_SBUS
+	case SNDRV_DMA_TYPE_SBUS:
+		return a->dev.sbus == b->dev.sbus;
+#endif
+	}
+	return 0;
+}
+
+/**
+ * snd_dma_alloc_pages - allocate the buffer area according to the given type
+ * @dev: the buffer device info
+ * @size: the buffer size to allocate
+ * @dmab: buffer allocation record to store the allocated data
+ *
+ * Calls the memory-allocator function for the corresponding
+ * buffer type.
+ * 
+ * Returns zero if the buffer with the given size is allocated successfuly,
+ * other a negative value at error.
+ */
+int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size,
+			struct snd_dma_buffer *dmab)
+{
+	snd_assert(dev != NULL, return -ENXIO);
+	snd_assert(size > 0, return -ENXIO);
+	snd_assert(dmab != NULL, return -ENXIO);
+
+	dmab->bytes = 0;
+	switch (dev->type) {
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		dmab->area = snd_malloc_pages(size, dev->dev.flags);
+		dmab->addr = 0;
+		break;
+#ifdef CONFIG_ISA
+	case SNDRV_DMA_TYPE_ISA:
+		dmab->area = snd_malloc_isa_pages(size, &dmab->addr);
+		break;
+#endif
+#ifdef CONFIG_PCI
+	case SNDRV_DMA_TYPE_PCI:
+		dmab->area = snd_malloc_pci_pages(dev->dev.pci, size, &dmab->addr);
+		break;
+	case SNDRV_DMA_TYPE_PCI_SG:
+		snd_malloc_sgbuf_pages(dev->dev.pci, size, dmab);
+		break;
+#endif
+#ifdef CONFIG_SBUS
+	case SNDRV_DMA_TYPE_SBUS:
+		dmab->area = snd_malloc_pci_pages(dev->dev.sbus, size, &dmab->addr);
+		break;
+#endif
+	default:
+		printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type);
+		dmab->area = NULL;
+		dmab->addr = 0;
+		return -ENXIO;
+	}
+	if (dmab->area)
+		dmab->bytes = size;
+	return 0;
+}
+
+
+/**
+ * snd_dma_free_pages - release the allocated buffer
+ * @dev: the buffer device info
+ * @dmbab: the buffer allocation record to release
+ *
+ * Releases the allocated buffer via snd_dma_alloc_pages().
+ */
+void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab)
+{
+	switch (dev->type) {
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		snd_free_pages(dmab->area, dmab->bytes);
+		break;
+#ifdef CONFIG_ISA
+	case SNDRV_DMA_TYPE_ISA:
+		snd_free_isa_pages(dmab->bytes, dmab->area, dmab->addr);
+		break;
+#endif
+#ifdef CONFIG_PCI
+	case SNDRV_DMA_TYPE_PCI:
+		snd_free_pci_pages(dev->dev.pci, dmab->bytes, dmab->area, dmab->addr);
+		break;
+	case SNDRV_DMA_TYPE_PCI_SG:
+		snd_free_sgbuf_pages(dmab);
+		break;
+#endif
+#ifdef CONFIG_SBUS
+	case SNDRV_DMA_TYPE_SBUS:
+		snd_free_sbus_pages(dev->dev.sbus, dmab->size, dmab->are, dmab->addr);
+		break;
+#endif
+	default:
+		printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type);
+	}
+}
+
+
+/*
+ * search for the device
+ */
+static struct snd_mem_list *mem_list_find(const struct snd_dma_device *dev)
+{
+	struct list_head *p;
+	struct snd_mem_list *mem;
+
+	list_for_each(p, &mem_list_head) {
+		mem = list_entry(p, struct snd_mem_list, list);
+		if (compare_device(&mem->dev, dev))
+			return mem;
+	}
+	return NULL;
+}
+
+/**
+ * snd_dma_get_reserved - get the reserved buffer for the given device
+ * @dev: the buffer device info
+ * @dmab: the buffer allocation record to store
+ *
+ * Looks for the reserved-buffer list and re-uses if the same buffer
+ * is found in the list.  When the buffer is found, it's marked as used.
+ * For unmarking the buffer, call snd_dma_free_reserved().
+ *
+ * Returns the size of buffer if the buffer is found, or zero if not found.
+ */
+size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab)
+{
+	struct snd_mem_list *mem;
+
+	snd_assert(dev && dmab, return 0);
+
+	down(&list_mutex);
+	mem = mem_list_find(dev);
+	if (mem) {
+		mem->used = 1;
+		*dmab = mem->buffer;
+		up(&list_mutex);
+		return dmab->bytes;
+	}
+	up(&list_mutex);
+	return 0;
+}
+
+/**
+ * snd_dma_free_reserved - unmark the reserved buffer
+ * @dev: the buffer device info
+ *
+ * Looks for the matching reserved buffer and erases the mark on it
+ * if found.
+ *
+ * Returns zero.
+ */
+int snd_dma_free_reserved(const struct snd_dma_device *dev)
+{
+	struct snd_mem_list *mem;
+
+	snd_assert(dev, return -EINVAL);
+	down(&list_mutex);
+	mem = mem_list_find(dev);
+	if (mem)
+		mem->used = 0;
+	up(&list_mutex);
+	return 0;
+}
+
+/**
+ * snd_dma_set_reserved - reserve the buffer
+ * @dev: the buffer device info
+ * @dmab: the buffer to reserve
+ *
+ * Reserves the given buffer as a reserved buffer.
+ * When an old reserved buffer already exists, the old one is released
+ * and replaced with the new one.
+ *
+ * When NULL buffer pointer or zero buffer size is given, the existing
+ * release buffer is released and the entry is removed.
+ * 
+ * Returns zero if successful, or a negative code at error.
+ */
+int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab)
+{
+	struct snd_mem_list *mem;
+
+	snd_assert(dev, return -EINVAL);
+	down(&list_mutex);
+	mem = mem_list_find(dev);
+	if (mem) {
+		snd_dma_free_pages(dev, &mem->buffer);
+		if (! dmab || ! dmab->bytes) {
+			/* remove the entry */
+			list_del(&mem->list);
+			kfree(mem);
+			up(&list_mutex);
+			return 0;
+		}
+	} else {
+		if (! dmab || ! dmab->bytes) {
+			up(&list_mutex);
+			return 0;
+		}
+		mem = kmalloc(sizeof(*mem), GFP_KERNEL);
+		mem->dev = *dev;
+		list_add(&mem->list, &mem_list_head);
+	}
+	/* store the entry */
+	mem->used = 1;
+	mem->buffer = *dmab;
+	up(&list_mutex);
+	return 0;
+}
+
+/*
+ * purge all reserved buffers
+ */
+static void free_all_reserved_pages(void)
+{
+	struct list_head *p;
+	struct snd_mem_list *mem;
+
+	down(&list_mutex);
+	while (! list_empty(&mem_list_head)) {
+		p = mem_list_head.next;
+		mem = list_entry(p, struct snd_mem_list, list);
+		list_del(p);
+		snd_dma_free_pages(&mem->dev, &mem->buffer);
+		kfree(mem);
+	}
+	up(&list_mutex);
+}
+
+
+/*
+ *
+ *  Generic memory allocators
+ *
+ */
+
+static long snd_allocated_pages; /* holding the number of allocated pages */
+
+static void mark_pages(void *res, int order)
+{
+	struct page *page = virt_to_page(res);
+	struct page *last_page = page + (1 << order);
+	while (page < last_page)
+		SetPageReserved(page++);
+	snd_allocated_pages += 1 << order;
+}
+
+static void unmark_pages(void *res, int order)
+{
+	struct page *page = virt_to_page(res);
+	struct page *last_page = page + (1 << order);
+	while (page < last_page)
+		ClearPageReserved(page++);
+	snd_allocated_pages -= 1 << order;
+}
+
+/**
+ * snd_malloc_pages - allocate pages with the given size
+ * @size: the size to allocate in bytes
+ * @gfp_flags: the allocation conditions, GFP_XXX
+ *
+ * Allocates the physically contiguous pages with the given size.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_pages(size_t size, unsigned int gfp_flags)
+{
+	int pg;
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(gfp_flags != 0, return NULL);
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) {
+		mark_pages(res, pg);
+	}
+	return res;
+}
+
+/**
+ * snd_malloc_pages_fallback - allocate pages with the given size with fallback
+ * @size: the requested size to allocate in bytes
+ * @gfp_flags: the allocation conditions, GFP_XXX
+ * @res_size: the pointer to store the size of buffer actually allocated
+ *
+ * Allocates the physically contiguous pages with the given request
+ * size.  When no space is left, this function reduces the size and
+ * tries to allocate again.  The size actually allocated is stored in
+ * res_size argument.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size)
+{
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(res_size != NULL, return NULL);
+	do {
+		if ((res = snd_malloc_pages(size, gfp_flags)) != NULL) {
+			*res_size = size;
+			return res;
+		}
+		size >>= 1;
+	} while (size >= PAGE_SIZE);
+	return NULL;
+}
+
+/**
+ * snd_free_pages - release the pages
+ * @ptr: the buffer pointer to release
+ * @size: the allocated buffer size
+ *
+ * Releases the buffer allocated via snd_malloc_pages().
+ */
+void snd_free_pages(void *ptr, size_t size)
+{
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	unmark_pages(ptr, pg);
+	free_pages((unsigned long) ptr, pg);
+}
+
+#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
+
+/**
+ * snd_malloc_isa_pages - allocate pages for ISA bus with the given size
+ * @size: the size to allocate in bytes
+ * @dma_addr: the pointer to store the physical address of the buffer
+ *
+ * Allocates the physically contiguous pages with the given size for
+ * ISA bus.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr)
+{
+	void *dma_area;
+	dma_area = snd_malloc_pages(size, GFP_ATOMIC|GFP_DMA);
+	*dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
+	return dma_area;
+}
+
+/**
+ * snd_malloc_isa_pages_fallback - allocate pages with the given size with fallback for ISA bus
+ * @size: the requested size to allocate in bytes
+ * @dma_addr: the pointer to store the physical address of the buffer
+ * @res_size: the pointer to store the size of buffer actually allocated
+ *
+ * Allocates the physically contiguous pages with the given request
+ * size for PCI bus.  When no space is left, this function reduces the size and
+ * tries to allocate again.  The size actually allocated is stored in
+ * res_size argument.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_isa_pages_fallback(size_t size,
+				    dma_addr_t *dma_addr,
+				    size_t *res_size)
+{
+	void *dma_area;
+	dma_area = snd_malloc_pages_fallback(size, GFP_ATOMIC|GFP_DMA, res_size);
+	*dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
+	return dma_area;
+}
+
+#endif /* CONFIG_ISA && !CONFIG_PCI */
+
+#ifdef CONFIG_PCI
+
+/**
+ * snd_malloc_pci_pages - allocate pages for PCI bus with the given size
+ * @pci: the pci device pointer
+ * @size: the size to allocate in bytes
+ * @dma_addr: the pointer to store the physical address of the buffer
+ *
+ * Allocates the physically contiguous pages with the given size for
+ * PCI bus.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_pci_pages(struct pci_dev *pci,
+			   size_t size,
+			   dma_addr_t *dma_addr)
+{
+	int pg;
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(dma_addr != NULL, return NULL);
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	res = pci_alloc_consistent(pci, PAGE_SIZE * (1 << pg), dma_addr);
+	if (res != NULL) {
+		mark_pages(res, pg);
+	}
+	return res;
+}
+
+/**
+ * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for PCI bus
+ * @pci: pci device pointer
+ * @size: the requested size to allocate in bytes
+ * @dma_addr: the pointer to store the physical address of the buffer
+ * @res_size: the pointer to store the size of buffer actually allocated
+ *
+ * Allocates the physically contiguous pages with the given request
+ * size for PCI bus.  When no space is left, this function reduces the size and
+ * tries to allocate again.  The size actually allocated is stored in
+ * res_size argument.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_pci_pages_fallback(struct pci_dev *pci,
+				    size_t size,
+				    dma_addr_t *dma_addr,
+				    size_t *res_size)
+{
+	void *res;
+
+	snd_assert(res_size != NULL, return NULL);
+	do {
+		if ((res = snd_malloc_pci_pages(pci, size, dma_addr)) != NULL) {
+			*res_size = size;
+			return res;
+		}
+		size >>= 1;
+	} while (size >= PAGE_SIZE);
+	return NULL;
+}
+
+/**
+ * snd_free_pci_pages - release the pages
+ * @pci: pci device pointer
+ * @size: the allocated buffer size
+ * @ptr: the buffer pointer to release
+ * @dma_addr: the physical address of the buffer
+ *
+ * Releases the buffer allocated via snd_malloc_pci_pages().
+ */
+void snd_free_pci_pages(struct pci_dev *pci,
+			size_t size,
+			void *ptr,
+			dma_addr_t dma_addr)
+{
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	unmark_pages(ptr, pg);
+	pci_free_consistent(pci, PAGE_SIZE * (1 << pg), ptr, dma_addr);
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(__i386__)
+/*
+ * on ix86, we allocate a page with GFP_KERNEL to assure the
+ * allocation.  the code is almost same with kernel/i386/pci-dma.c but
+ * it allocates only a single page and checks the validity of the
+ * page address with the given pci dma mask.
+ */
+
+/**
+ * snd_malloc_pci_page - allocate a page in the valid pci dma mask
+ * @pci: pci device pointer
+ * @addrp: the pointer to store the physical address of the buffer
+ *
+ * Allocates a single page for the given PCI device and returns
+ * the virtual address and stores the physical address on addrp.
+ * 
+ * This function cannot be called from interrupt handlers or
+ * within spinlocks.
+ */
+void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
+{
+	void *ptr;
+	dma_addr_t addr;
+	unsigned long rmask;
+
+	rmask = ~(unsigned long)(pci ? pci->dma_mask : 0x00ffffff);
+	ptr = (void *)__get_free_page(GFP_KERNEL);
+	if (ptr) {
+		addr = virt_to_phys(ptr);
+		if (((unsigned long)addr + PAGE_SIZE - 1) & rmask) {
+			/* try to reallocate with the GFP_DMA */
+			free_page((unsigned long)ptr);
+			/* use GFP_ATOMIC for the DMA zone to avoid stall */
+			ptr = (void *)__get_free_page(GFP_ATOMIC | GFP_DMA);
+			if (ptr) /* ok, the address must be within lower 16MB... */
+				addr = virt_to_phys(ptr);
+			else
+				addr = 0;
+		}
+	} else
+		addr = 0;
+	if (ptr) {
+		memset(ptr, 0, PAGE_SIZE);
+		mark_pages(ptr, 0);
+	}
+	*addrp = addr;
+	return ptr;
+}
+#else
+
+/* on other architectures, call snd_malloc_pci_pages() helper function
+ * which uses pci_alloc_consistent().
+ */
+void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
+{
+	return snd_malloc_pci_pages(pci, PAGE_SIZE, addrp);
+}
+
+#endif
+
+#if 0 /* for kernel-doc */
+/**
+ * snd_free_pci_page - release a page
+ * @pci: pci device pointer
+ * @ptr: the buffer pointer to release
+ * @dma_addr: the physical address of the buffer
+ *
+ * Releases the buffer allocated via snd_malloc_pci_page().
+ */
+void snd_free_pci_page(struct pci_dev *pci, void *ptr, dma_addr_t dma_addr);
+#endif /* for kernel-doc */
+
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_SBUS
+
+/**
+ * snd_malloc_sbus_pages - allocate pages for SBUS with the given size
+ * @sdev: sbus device pointer
+ * @size: the size to allocate in bytes
+ * @dma_addr: the pointer to store the physical address of the buffer
+ *
+ * Allocates the physically contiguous pages with the given size for
+ * SBUS.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_sbus_pages(struct sbus_dev *sdev,
+			    size_t size,
+			    dma_addr_t *dma_addr)
+{
+	int pg;
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(dma_addr != NULL, return NULL);
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
+	if (res != NULL) {
+		mark_pages(res, pg);
+	}
+	return res;
+}
+
+/**
+ * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for SBUS
+ * @sdev: sbus device pointer
+ * @size: the requested size to allocate in bytes
+ * @dma_addr: the pointer to store the physical address of the buffer
+ * @res_size: the pointer to store the size of buffer actually allocated
+ *
+ * Allocates the physically contiguous pages with the given request
+ * size for SBUS.  When no space is left, this function reduces the size and
+ * tries to allocate again.  The size actually allocated is stored in
+ * res_size argument.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev,
+				     size_t size,
+				     dma_addr_t *dma_addr,
+				     size_t *res_size)
+{
+	void *res;
+
+	snd_assert(res_size != NULL, return NULL);
+	do {
+		if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) {
+			*res_size = size;
+			return res;
+		}
+		size >>= 1;
+	} while (size >= PAGE_SIZE);
+	return NULL;
+}
+
+/**
+ * snd_free_sbus_pages - release the pages
+ * @sdev: sbus device pointer
+ * @size: the allocated buffer size
+ * @ptr: the buffer pointer to release
+ * @dma_addr: the physical address of the buffer
+ *
+ * Releases the buffer allocated via snd_malloc_pci_pages().
+ */
+void snd_free_sbus_pages(struct sbus_dev *sdev,
+			 size_t size,
+			 void *ptr,
+			 dma_addr_t dma_addr)
+{
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	unmark_pages(ptr, pg);
+	sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
+}
+
+#endif /* CONFIG_SBUS */
+
+
+#ifdef CONFIG_PROC_FS
+/*
+ * proc file interface
+ */
+static int snd_mem_proc_read(char *page, char **start, off_t off,
+			     int count, int *eof, void *data)
+{
+	int len = 0;
+	long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
+
+	len += sprintf(page + len, "pages  : %li bytes (%li pages per %likB)\n",
+		       pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
+	return len;
+}
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * module entry
+ */
+
+static int __init snd_mem_init(void)
+{
+	create_proc_read_entry("driver/snd-page-alloc", 0, 0, snd_mem_proc_read, NULL);
+	return 0;
+}
+
+static void __exit snd_mem_exit(void)
+{
+	remove_proc_entry("driver/snd-page-alloc", NULL);
+	free_all_reserved_pages();
+	if (snd_allocated_pages > 0)
+		printk(KERN_ERR "snd-malloc: Memory leak?  pages not freed = %li\n", snd_allocated_pages);
+}
+
+
+module_init(snd_mem_init)
+module_exit(snd_mem_exit)
+
+
+/*
+ * exports
+ */
+EXPORT_SYMBOL(snd_dma_alloc_pages);
+EXPORT_SYMBOL(snd_dma_free_pages);
+EXPORT_SYMBOL(snd_dma_get_reserved);
+EXPORT_SYMBOL(snd_dma_free_reserved);
+EXPORT_SYMBOL(snd_dma_set_reserved);
+
+EXPORT_SYMBOL(snd_malloc_pages);
+EXPORT_SYMBOL(snd_malloc_pages_fallback);
+EXPORT_SYMBOL(snd_free_pages);
+#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
+EXPORT_SYMBOL(snd_malloc_isa_pages);
+EXPORT_SYMBOL(snd_malloc_isa_pages_fallback);
+#endif
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(snd_malloc_pci_pages);
+EXPORT_SYMBOL(snd_malloc_pci_pages_fallback);
+EXPORT_SYMBOL(snd_malloc_pci_page);
+EXPORT_SYMBOL(snd_free_pci_pages);
+EXPORT_SYMBOL(snd_malloc_sgbuf_pages);
+EXPORT_SYMBOL(snd_free_sgbuf_pages);
+#ifdef HACK_PCI_ALLOC_CONSISTENT
+EXPORT_SYMBOL(snd_pci_hack_alloc_consistent);
+#endif 
+#endif
+#ifdef CONFIG_SBUS
+EXPORT_SYMBOL(snd_malloc_sbus_pages);
+EXPORT_SYMBOL(snd_malloc_sbus_pages_fallback);
+EXPORT_SYMBOL(snd_free_sbus_pages);
+#endif
diff -urN linux-2.5.65-bk1/sound/core/memory.c linux-2.5.65-bk2/sound/core/memory.c
--- linux-2.5.65-bk1/sound/core/memory.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/sound/core/memory.c	Mon Mar 31 12:39:51 2003
@@ -1,6 +1,7 @@
 /*
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *  Memory allocation routines.
+ * 
+ *  Memory allocation helpers.
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -28,9 +29,6 @@
 #include <linux/pci.h>
 #include <sound/core.h>
 #include <sound/info.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
 
 /*
  *  memory allocation helpers and debug routines
@@ -48,7 +46,6 @@
 
 #define snd_alloc_track_entry(obj) (struct snd_alloc_track *)((char*)obj - (unsigned long)((struct snd_alloc_track *)0)->data)
 
-static long snd_alloc_pages;
 static long snd_alloc_kmalloc;
 static long snd_alloc_vmalloc;
 static LIST_HEAD(snd_alloc_kmalloc_list);
@@ -61,7 +58,6 @@
 
 void snd_memory_init(void)
 {
-	snd_alloc_pages = 0;
 	snd_alloc_kmalloc = 0;
 	snd_alloc_vmalloc = 0;
 }
@@ -70,8 +66,7 @@
 {
 	struct list_head *head;
 	struct snd_alloc_track *t;
-	if (snd_alloc_pages > 0)
-		snd_printk(KERN_ERR "Not freed snd_alloc_pages = %li\n", snd_alloc_pages);
+
 	if (snd_alloc_kmalloc > 0)
 		snd_printk(KERN_ERR "Not freed snd_alloc_kmalloc = %li\n", snd_alloc_kmalloc);
 	if (snd_alloc_vmalloc > 0)
@@ -226,8 +221,6 @@
 
 static void snd_memory_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
 {
-	long pages = snd_alloc_pages >> (PAGE_SHIFT-12);
-	snd_iprintf(buffer, "pages  : %li bytes (%li pages per %likB)\n", pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
 	snd_iprintf(buffer, "kmalloc: %li bytes\n", snd_alloc_kmalloc);
 	snd_iprintf(buffer, "vmalloc: %li bytes\n", snd_alloc_vmalloc);
 }
@@ -263,335 +256,6 @@
 
 #endif /* CONFIG_SND_DEBUG_MEMORY */
 
-
-/**
- * snd_malloc_pages - allocate pages with the given size
- * @size: the size to allocate in bytes
- * @dma_flags: the allocation conditions, GFP_XXX
- *
- * Allocates the physically contiguous pages with the given size.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pages(unsigned long size, unsigned int dma_flags)
-{
-	int pg;
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(dma_flags != 0, return NULL);
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	if ((res = (void *) __get_free_pages(dma_flags, pg)) != NULL) {
-		struct page *page = virt_to_page(res);
-		struct page *last_page = page + (1 << pg);
-		while (page < last_page)
-			SetPageReserved(page++);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-		snd_alloc_pages += 1 << pg;
-#endif
-	}
-	return res;
-}
-
-/**
- * snd_malloc_pages_fallback - allocate pages with the given size with fallback
- * @size: the requested size to allocate in bytes
- * @dma_flags: the allocation conditions, GFP_XXX
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size.  When no space is left, this function reduces the size and
- * tries to allocate again.  The size actually allocated is stored in
- * res_size argument.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pages_fallback(unsigned long size, unsigned int dma_flags, unsigned long *res_size)
-{
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(res_size != NULL, return NULL);
-	do {
-		if ((res = snd_malloc_pages(size, dma_flags)) != NULL) {
-			*res_size = size;
-			return res;
-		}
-		size >>= 1;
-	} while (size >= PAGE_SIZE);
-	return NULL;
-}
-
-/**
- * snd_free_pages - release the pages
- * @ptr: the buffer pointer to release
- * @size: the allocated buffer size
- *
- * Releases the buffer allocated via snd_malloc_pages().
- */
-void snd_free_pages(void *ptr, unsigned long size)
-{
-	int pg;
-	struct page *page, *last_page;
-
-	if (ptr == NULL)
-		return;
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	page = virt_to_page(ptr);
-	last_page = page + (1 << pg);
-	while (page < last_page)
-		ClearPageReserved(page++);
-	free_pages((unsigned long) ptr, pg);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-	snd_alloc_pages -= 1 << pg;
-#endif
-}
-
-#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
-
-/**
- * snd_malloc_isa_pages - allocate pages for ISA bus with the given size
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * ISA bus.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_isa_pages(unsigned long size, dma_addr_t *dma_addr)
-{
-	void *dma_area;
-	dma_area = snd_malloc_pages(size, GFP_ATOMIC|GFP_DMA);
-	*dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
-	return dma_area;
-}
-
-/**
- * snd_malloc_isa_pages_fallback - allocate pages with the given size with fallback for ISA bus
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for PCI bus.  When no space is left, this function reduces the size and
- * tries to allocate again.  The size actually allocated is stored in
- * res_size argument.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_isa_pages_fallback(unsigned long size,
-				    dma_addr_t *dma_addr,
-				    unsigned long *res_size)
-{
-	void *dma_area;
-	dma_area = snd_malloc_pages_fallback(size, GFP_ATOMIC|GFP_DMA, res_size);
-	*dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
-	return dma_area;
-}
-
-#endif /* CONFIG_ISA && !CONFIG_PCI */
-
-#ifdef CONFIG_PCI
-
-/**
- * snd_malloc_pci_pages - allocate pages for PCI bus with the given size
- * @pci: the pci device pointer
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * PCI bus.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pci_pages(struct pci_dev *pci,
-			   unsigned long size,
-			   dma_addr_t *dma_addr)
-{
-	int pg;
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(dma_addr != NULL, return NULL);
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	res = pci_alloc_consistent(pci, PAGE_SIZE * (1 << pg), dma_addr);
-	if (res != NULL) {
-		struct page *page = virt_to_page(res);
-		struct page *last_page = page + (1 << pg);
-		while (page < last_page)
-			SetPageReserved(page++);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-		snd_alloc_pages += 1 << pg;
-#endif
-	}
-	return res;
-}
-
-/**
- * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for PCI bus
- * @pci: pci device pointer
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for PCI bus.  When no space is left, this function reduces the size and
- * tries to allocate again.  The size actually allocated is stored in
- * res_size argument.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pci_pages_fallback(struct pci_dev *pci,
-				    unsigned long size,
-				    dma_addr_t *dma_addr,
-				    unsigned long *res_size)
-{
-	void *res;
-
-	snd_assert(res_size != NULL, return NULL);
-	do {
-		if ((res = snd_malloc_pci_pages(pci, size, dma_addr)) != NULL) {
-			*res_size = size;
-			return res;
-		}
-		size >>= 1;
-	} while (size >= PAGE_SIZE);
-	return NULL;
-}
-
-/**
- * snd_free_pci_pages - release the pages
- * @pci: pci device pointer
- * @size: the allocated buffer size
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_pages().
- */
-void snd_free_pci_pages(struct pci_dev *pci,
-			unsigned long size,
-			void *ptr,
-			dma_addr_t dma_addr)
-{
-	int pg;
-	struct page *page, *last_page;
-
-	if (ptr == NULL)
-		return;
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	page = virt_to_page(ptr);
-	last_page = page + (1 << pg);
-	while (page < last_page)
-		ClearPageReserved(page++);
-	pci_free_consistent(pci, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-	snd_alloc_pages -= 1 << pg;
-#endif
-}
-
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_SBUS
-
-/**
- * snd_malloc_sbus_pages - allocate pages for SBUS with the given size
- * @sdev: sbus device pointer
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * SBUS.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_sbus_pages(struct sbus_dev *sdev,
-			    unsigned long size,
-			    dma_addr_t *dma_addr)
-{
-	int pg;
-	void *res;
-
-	snd_assert(size > 0, return NULL);
-	snd_assert(dma_addr != NULL, return NULL);
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
-	if (res != NULL) {
-		struct page *page = virt_to_page(res);
-		struct page *last_page = page + (1 << pg);
-		while (page < last_page)
-			SetPageReserved(page++);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-		snd_alloc_pages += 1 << pg;
-#endif
-	}
-	return res;
-}
-
-/**
- * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for SBUS
- * @sdev: sbus device pointer
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for SBUS.  When no space is left, this function reduces the size and
- * tries to allocate again.  The size actually allocated is stored in
- * res_size argument.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev,
-				     unsigned long size,
-				     dma_addr_t *dma_addr,
-				     unsigned long *res_size)
-{
-	void *res;
-
-	snd_assert(res_size != NULL, return NULL);
-	do {
-		if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) {
-			*res_size = size;
-			return res;
-		}
-		size >>= 1;
-	} while (size >= PAGE_SIZE);
-	return NULL;
-}
-
-/**
- * snd_free_sbus_pages - release the pages
- * @sdev: sbus device pointer
- * @size: the allocated buffer size
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_pages().
- */
-void snd_free_sbus_pages(struct sbus_dev *sdev,
-			 unsigned long size,
-			 void *ptr,
-			 dma_addr_t dma_addr)
-{
-	int pg;
-	struct page *page, *last_page;
-
-	if (ptr == NULL)
-		return;
-	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-	page = virt_to_page(ptr);
-	last_page = page + (1 << pg);
-	while (page < last_page)
-		ClearPageReserved(page++);
-	sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-	snd_alloc_pages -= 1 << pg;
-#endif
-}
-
-#endif /* CONFIG_SBUS */
-
 /**
  * snd_kcalloc - memory allocation and zero-clear
  * @size: the size to allocate in bytes
@@ -695,81 +359,3 @@
 	return 0;
 #endif
 }
-
-
-#ifdef CONFIG_PCI
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(__i386__)
-/*
- * on ix86, we allocate a page with GFP_KERNEL to assure the
- * allocation.  the code is almost same with kernel/i386/pci-dma.c but
- * it allocates only a single page and checks the validity of the
- * page address with the given pci dma mask.
- */
-
-/**
- * snd_malloc_pci_page - allocate a page in the valid pci dma mask
- * @pci: pci device pointer
- * @addrp: the pointer to store the physical address of the buffer
- *
- * Allocates a single page for the given PCI device and returns
- * the virtual address and stores the physical address on addrp.
- * 
- * This function cannot be called from interrupt handlers or
- * within spinlocks.
- */
-void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
-{
-	void *ptr;
-	dma_addr_t addr;
-	unsigned long rmask;
-
-	rmask = ~(unsigned long)(pci ? pci->dma_mask : 0x00ffffff);
-	ptr = (void *)__get_free_page(GFP_KERNEL);
-	if (ptr) {
-		addr = virt_to_phys(ptr);
-		if (((unsigned long)addr + PAGE_SIZE - 1) & rmask) {
-			/* try to reallocate with the GFP_DMA */
-			free_page((unsigned long)ptr);
-			ptr = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
-			if (ptr) /* ok, the address must be within lower 16MB... */
-				addr = virt_to_phys(ptr);
-			else
-				addr = 0;
-		}
-	} else
-		addr = 0;
-	if (ptr) {
-		struct page *page = virt_to_page(ptr);
-		memset(ptr, 0, PAGE_SIZE);
-		SetPageReserved(page);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-		snd_alloc_pages++;
-#endif
-	}
-	*addrp = addr;
-	return ptr;
-}
-#else
-/* on other architectures, call snd_malloc_pci_pages() helper function
- * which uses pci_alloc_consistent().
- */
-void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
-{
-	return snd_malloc_pci_pages(pci, PAGE_SIZE, addrp);
-}
-#endif /* 2.4 && i386 */
-
-#if 0 /* for kernel-doc */
-/**
- * snd_free_pci_page - release a page
- * @pci: pci device pointer
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_page().
- */
-void snd_free_pci_page(struct pci_dev *pci, void *ptr, dma_addr_t dma_addr);
-#endif /* for kernel-doc */
-
-#endif /* CONFIG_PCI */
diff -urN linux-2.5.65-bk1/sound/core/memory_wrapper.c linux-2.5.65-bk2/sound/core/memory_wrapper.c
--- linux-2.5.65-bk1/sound/core/memory_wrapper.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/sound/core/memory_wrapper.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *                   Takashi Iwai <tiwai@suse.de>
+ * 
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <sound/memalloc.h>
+
+
+#ifdef HACK_PCI_ALLOC_CONSISTENT
+/*
+ * A dirty hack... when the kernel code is fixed this should be removed.
+ *
+ * since pci_alloc_consistent always tries GFP_DMA when the requested
+ * pci memory region is below 32bit, it happens quite often that even
+ * 2 order of pages cannot be allocated.
+ *
+ * so in the following, we allocate at first without dma_mask, so that
+ * allocation will be done without GFP_DMA.  if the area doesn't match
+ * with the requested region, then realloate with the original dma_mask
+ * again.
+ */
+
+void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
+				    dma_addr_t *dma_handle)
+{
+	void *ret;
+	u64 dma_mask;
+	unsigned long rmask;
+
+	if (hwdev == NULL)
+		return pci_alloc_consistent(hwdev, size, dma_handle);
+	dma_mask = hwdev->dma_mask;
+	rmask = ~((unsigned long)dma_mask);
+	hwdev->dma_mask = 0xffffffff; /* do without masking */
+	ret = pci_alloc_consistent(hwdev, size, dma_handle);
+	hwdev->dma_mask = dma_mask; /* restore */
+	if (ret) {
+		/* obtained address is out of range? */
+		if (((unsigned long)*dma_handle + size - 1) & rmask) {
+			/* reallocate with the proper mask */
+			pci_free_consistent(hwdev, size, ret, *dma_handle);
+			ret = pci_alloc_consistent(hwdev, size, dma_handle);
+		}
+	} else {
+		/* wish to success now with the proper mask... */
+		if (dma_mask != 0xffffffff)
+			ret = pci_alloc_consistent(hwdev, size, dma_handle);
+	}
+	return ret;
+}
+
+#endif /* HACK_PCI_ALLOC_CONSISTENT */
diff -urN linux-2.5.65-bk1/sound/core/misc.c linux-2.5.65-bk2/sound/core/misc.c
--- linux-2.5.65-bk1/sound/core/misc.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/sound/core/misc.c	Mon Mar 31 12:39:51 2003
@@ -77,27 +77,6 @@
 	va_end(args);
 	tmpbuf[sizeof(tmpbuf)-1] = '\0';
 	printk(tmpbuf);
-}
-#endif
 
-#if defined(CONFIG_SND_DEBUG) && !defined(CONFIG_SND_VERBOSE_PRINTK)
-void snd_printd(const char *format, ...)
-{
-	va_list args;
-	char tmpbuf[512];
-	
-	if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
-		char tmp[] = "<0>";
-		tmp[1] = format[1];
-		printk("%sALSA: ", tmp);
-		format += 3;
-	} else {
-		printk(KERN_DEBUG "ALSA: ");
-	}
-	va_start(args, format);
-	vsnprintf(tmpbuf, sizeof(tmpbuf)-1, format, args);
-	va_end(args);
-	tmpbuf[sizeof(tmpbuf)-1] = '\0';
-	printk(tmpbuf);
 }
 #endif
diff -urN linux-2.5.65-bk1/sound/core/oss/pcm_oss.c linux-2.5.65-bk2/sound/core/oss/pcm_oss.c
--- linux-2.5.65-bk1/sound/core/oss/pcm_oss.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/sound/core/oss/pcm_oss.c	Mon Mar 31 12:39:51 2003
@@ -294,8 +294,8 @@
 static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_pcm_hw_params_t params, sparams;
-	snd_pcm_sw_params_t sw_params;
+	snd_pcm_hw_params_t *params, *sparams;
+	snd_pcm_sw_params_t *sw_params;
 	ssize_t oss_buffer_size, oss_period_size;
 	size_t oss_frame_size;
 	int err;
@@ -304,6 +304,15 @@
 	snd_mask_t sformat_mask;
 	snd_mask_t mask;
 
+	sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
+	params = kmalloc(sizeof(*params), GFP_KERNEL);
+	sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
+	if (!sw_params || !params || !sparams) {
+		snd_printd("No memory\n");
+		err = -ENOMEM;
+		goto failure;
+	}
+
 	if (atomic_read(&runtime->mmap_count)) {
 		direct = 1;
 	} else {
@@ -311,9 +320,9 @@
 		direct = (setup != NULL && setup->direct);
 	}
 
-	_snd_pcm_hw_params_any(&sparams);
-	_snd_pcm_hw_param_setinteger(&sparams, SNDRV_PCM_HW_PARAM_PERIODS);
-	_snd_pcm_hw_param_min(&sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
+	_snd_pcm_hw_params_any(sparams);
+	_snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
+	_snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
 	snd_mask_none(&mask);
 	if (atomic_read(&runtime->mmap_count))
 		snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
@@ -322,17 +331,18 @@
 		if (!direct)
 			snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
 	}
-	err = snd_pcm_hw_param_mask(substream, &sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
+	err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
 	if (err < 0) {
 		snd_printd("No usable accesses\n");
-		return -EINVAL;
+		err = -EINVAL;
+		goto failure;
 	}
-	choose_rate(substream, &sparams, runtime->oss.rate);
-	snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, 0);
+	choose_rate(substream, sparams, runtime->oss.rate);
+	snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, 0);
 
 	format = snd_pcm_oss_format_from(runtime->oss.format);
 
-	sformat_mask = *hw_param_mask(&sparams, SNDRV_PCM_HW_PARAM_FORMAT);
+	sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
 	if (direct)
 		sformat = format;
 	else
@@ -346,52 +356,53 @@
 		}
 		if (sformat > SNDRV_PCM_FORMAT_LAST) {
 			snd_printd("Cannot find a format!!!\n");
-			return -EINVAL;
+			err = -EINVAL;
+			goto failure;
 		}
 	}
-	err = _snd_pcm_hw_param_set(&sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
-	snd_assert(err >= 0, return err);
+	err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
+	snd_assert(err >= 0, goto failure);
 
 	if (direct) {
-		params = sparams;
+		memcpy(params, sparams, sizeof(*params));
 	} else {
-		_snd_pcm_hw_params_any(&params);
-		_snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_ACCESS,
+		_snd_pcm_hw_params_any(params);
+		_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
 				      SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
-		_snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FORMAT,
+		_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
 				      snd_pcm_oss_format_from(runtime->oss.format), 0);
-		_snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
+		_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
 				      runtime->oss.channels, 0);
-		_snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_RATE,
+		_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
 				      runtime->oss.rate, 0);
 		pdprintf("client: access = %i, format = %i, channels = %i, rate = %i\n",
-			 params_access(&params), params_format(&params),
-			 params_channels(&params), params_rate(&params));
+			 params_access(params), params_format(params),
+			 params_channels(params), params_rate(params));
 	}
 	pdprintf("slave: access = %i, format = %i, channels = %i, rate = %i\n",
-		 params_access(&sparams), params_format(&sparams),
-		 params_channels(&sparams), params_rate(&sparams));
+		 params_access(sparams), params_format(sparams),
+		 params_channels(sparams), params_rate(sparams));
 
-	oss_frame_size = snd_pcm_format_physical_width(params_format(&params)) *
-			 params_channels(&params) / 8;
+	oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
+			 params_channels(params) / 8;
 
 	snd_pcm_oss_plugin_clear(substream);
 	if (!direct) {
 		/* add necessary plugins */
 		snd_pcm_oss_plugin_clear(substream);
 		if ((err = snd_pcm_plug_format_plugins(substream,
-						       &params, 
-						       &sparams)) < 0) {
+						       params, 
+						       sparams)) < 0) {
 			snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err);
 			snd_pcm_oss_plugin_clear(substream);
-			return err;
+			goto failure;
 		}
 		if (runtime->oss.plugin_first) {
 			snd_pcm_plugin_t *plugin;
-			if ((err = snd_pcm_plugin_build_io(substream, &sparams, &plugin)) < 0) {
+			if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) {
 				snd_printd("snd_pcm_plugin_build_io failed: %i\n", err);
 				snd_pcm_oss_plugin_clear(substream);
-				return err;
+				goto failure;
 			}
 			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 				err = snd_pcm_plugin_append(plugin);
@@ -400,66 +411,66 @@
 			}
 			if (err < 0) {
 				snd_pcm_oss_plugin_clear(substream);
-				return err;
+				goto failure;
 			}
 		}
 	}
 
-	err = snd_pcm_oss_period_size(substream, &params, &sparams);
+	err = snd_pcm_oss_period_size(substream, params, sparams);
 	if (err < 0)
-		return err;
+		goto failure;
 
 	n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
-	err = snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, 0);
-	snd_assert(err >= 0, return err);
+	err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, 0);
+	snd_assert(err >= 0, goto failure);
 
-	err = snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_PERIODS,
+	err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
 				     runtime->oss.periods, 0);
-	snd_assert(err >= 0, return err);
+	snd_assert(err >= 0, goto failure);
 
 	snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, 0);
 
-	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, &sparams)) < 0) {
+	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) {
 		snd_printd("HW_PARAMS failed: %i\n", err);
-		return err;
+		goto failure;
 	}
 
-	memset(&sw_params, 0, sizeof(sw_params));
+	memset(sw_params, 0, sizeof(*sw_params));
 	if (runtime->oss.trigger) {
-		sw_params.start_threshold = 1;
+		sw_params->start_threshold = 1;
 	} else {
-		sw_params.start_threshold = runtime->boundary;
+		sw_params->start_threshold = runtime->boundary;
 	}
 	if (atomic_read(&runtime->mmap_count))
-		sw_params.stop_threshold = runtime->boundary;
+		sw_params->stop_threshold = runtime->boundary;
 	else
-		sw_params.stop_threshold = runtime->buffer_size;
-	sw_params.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
-	sw_params.period_step = 1;
-	sw_params.sleep_min = 0;
-	sw_params.avail_min = runtime->period_size;
-	sw_params.xfer_align = 1;
-	sw_params.silence_threshold = 0;
-	sw_params.silence_size = 0;
+		sw_params->stop_threshold = runtime->buffer_size;
+	sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+	sw_params->period_step = 1;
+	sw_params->sleep_min = 0;
+	sw_params->avail_min = runtime->period_size;
+	sw_params->xfer_align = 1;
+	sw_params->silence_threshold = 0;
+	sw_params->silence_size = 0;
 
-	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, &sw_params)) < 0) {
+	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
 		snd_printd("SW_PARAMS failed: %i\n", err);
-		return err;
+		goto failure;
 	}
 	runtime->control->avail_min = runtime->period_size;
 
-	runtime->oss.periods = params_periods(&sparams);
-	oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(&sparams));
-	snd_assert(oss_period_size >= 0, return -EINVAL);
+	runtime->oss.periods = params_periods(sparams);
+	oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
+	snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
 	if (runtime->oss.plugin_first) {
 		err = snd_pcm_plug_alloc(substream, oss_period_size);
 		if (err < 0)
-			return err;
+			goto failure;
 	}
 	oss_period_size *= oss_frame_size;
 
 	oss_buffer_size = oss_period_size * runtime->oss.periods;
-	snd_assert(oss_buffer_size >= 0, return -EINVAL);
+	snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);
 
 	runtime->oss.period_bytes = oss_period_size;
 	runtime->oss.buffer_bytes = oss_buffer_size;
@@ -468,12 +479,12 @@
 		 runtime->oss.period_bytes,
 		 runtime->oss.buffer_bytes);
 	pdprintf("slave: period_size = %i, buffer_size = %i\n",
-		 params_period_size(&sparams),
-		 params_buffer_size(&sparams));
+		 params_period_size(sparams),
+		 params_buffer_size(sparams));
 
-	runtime->oss.format = snd_pcm_oss_format_to(params_format(&params));
-	runtime->oss.channels = params_channels(&params);
-	runtime->oss.rate = params_rate(&params);
+	runtime->oss.format = snd_pcm_oss_format_to(params_format(params));
+	runtime->oss.channels = params_channels(params);
+	runtime->oss.rate = params_rate(params);
 
 	runtime->oss.params = 0;
 	runtime->oss.prepare = 1;
@@ -483,7 +494,16 @@
 	runtime->oss.buffer_used = 0;
 	if (runtime->dma_area)
 		snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
-	return 0;
+
+	err = 0;
+failure:
+	if (sw_params)
+		kfree(sw_params);
+	if (params)
+		kfree(params);
+	if (sparams)
+		kfree(sparams);
+	return err;
 }
 
 static int snd_pcm_oss_get_active_substream(snd_pcm_oss_file_t *pcm_oss_file, snd_pcm_substream_t **r_substream)
@@ -1460,9 +1480,12 @@
 		if (snd_pcm_running(substream))
 			snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
 		spin_unlock_irq(&runtime->lock);
-		if (substream->ops->hw_free != NULL)
-			substream->ops->hw_free(substream);
-		substream->ops->close(substream);
+		if (substream->open_flag) {
+			if (substream->ops->hw_free != NULL)
+				substream->ops->hw_free(substream);
+			substream->ops->close(substream);
+			substream->open_flag = 0;
+		}
 		substream->ffile = NULL;
 		snd_pcm_oss_release_substream(substream);
 		snd_pcm_release_substream(substream);
@@ -1526,6 +1549,7 @@
 			snd_pcm_oss_release_file(pcm_oss_file);
 			return err;
 		}
+		psubstream->open_flag = 1;
 		err = snd_pcm_hw_constraints_complete(psubstream);
 		if (err < 0) {
 			snd_printd("snd_pcm_hw_constraint_complete failed\n");
@@ -1547,6 +1571,7 @@
 			snd_pcm_oss_release_file(pcm_oss_file);
 			return err;
 		}
+		csubstream->open_flag = 1;
 		err = snd_pcm_hw_constraints_complete(csubstream);
 		if (err < 0) {
 			snd_printd("snd_pcm_hw_constraint_complete failed\n");
diff -urN linux-2.5.65-bk1/sound/core/pcm.c linux-2.5.65-bk2/sound/core/pcm.c
--- linux-2.5.65-bk1/sound/core/pcm.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/sound/core/pcm.c	Mon Mar 31 12:39:51 2003
@@ -386,10 +386,10 @@
 		return;
 	}
 	snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
-	snd_iprintf(buffer, "trigger_time: %ld.%06ld\n",
-		status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_usec);
-	snd_iprintf(buffer, "tstamp      : %ld.%06ld\n",
-		status.tstamp.tv_sec, status.tstamp.tv_usec);
+	snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
+		status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
+	snd_iprintf(buffer, "tstamp      : %ld.%09ld\n",
+		status.tstamp.tv_sec, status.tstamp.tv_nsec);
 	snd_iprintf(buffer, "delay       : %ld\n", status.delay);
 	snd_iprintf(buffer, "avail       : %ld\n", status.avail);
 	snd_iprintf(buffer, "avail_max   : %ld\n", status.avail_max);
@@ -595,8 +595,6 @@
 			snd_magic_kfree(substream);
 			return err;
 		}
-		substream->dma_type = SNDRV_PCM_DMA_TYPE_UNKNOWN;
-		substream->dma_private = NULL;
 		spin_lock_init(&substream->timer_lock);
 		prev = substream;
 	}
diff -urN linux-2.5.65-bk1/sound/core/pcm_lib.c linux-2.5.65-bk2/sound/core/pcm_lib.c
--- linux-2.5.65-bk1/sound/core/pcm_lib.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/sound/core/pcm_lib.c	Mon Mar 31 12:39:51 2003
@@ -137,7 +137,7 @@
 	old_hw_ptr = runtime->status->hw_ptr;
 	pos = substream->ops->pointer(substream);
 	if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
-		snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp);
+		snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec);
 #ifdef CONFIG_SND_DEBUG
 	if (pos >= runtime->buffer_size) {
 		snd_printk(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
@@ -198,7 +198,7 @@
 	old_hw_ptr = runtime->status->hw_ptr;
 	pos = substream->ops->pointer(substream);
 	if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
-		snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp);
+		snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec);
 #ifdef CONFIG_SND_DEBUG
 	if (pos >= runtime->buffer_size) {
 		snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
@@ -2186,6 +2186,8 @@
 		} else {
 			runtime->control->appl_ptr = appl_ptr;
 		}
+		if (substream->ops->ack)
+			substream->ops->ack(substream);
 
 		offset += frames;
 		size -= frames;
@@ -2478,6 +2480,8 @@
 		} else {
 			runtime->control->appl_ptr = appl_ptr;
 		}
+		if (substream->ops->ack)
+			substream->ops->ack(substream);
 
 		offset += frames;
 		size -= frames;
@@ -2654,6 +2658,9 @@
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages);
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages_for_all);
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages);
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages_for_all);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
 #endif
 #ifdef CONFIG_SBUS
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages);
diff -urN linux-2.5.65-bk1/sound/core/pcm_memory.c linux-2.5.65-bk2/sound/core/pcm_memory.c
--- linux-2.5.65-bk1/sound/core/pcm_memory.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/sound/core/pcm_memory.c	Mon Mar 31 12:39:51 2003
@@ -26,9 +26,6 @@
 #include <sound/pcm.h>
 #include <sound/info.h>
 #include <sound/initval.h>
-#ifdef CONFIG_PCI
-#include <sound/pcm_sgbuf.h>
-#endif
 
 static int preallocate_dma = 1;
 MODULE_PARM(preallocate_dma, "i");
@@ -44,59 +41,33 @@
 
 
 /*
- * allocate pages on the specified bus
- */
-static int alloc_pcm_pages(snd_pcm_substream_t *substream, size_t size,
-			   struct snd_pcm_dma_buffer *dmab)
-{
-	switch (substream->dma_type) {
-	case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
-		dmab->area = snd_malloc_pages(size, (unsigned int)((unsigned long)substream->dma_private & 0xffffffff));
-		dmab->addr = 0UL;		/* not valid */
-		break;
-#ifdef CONFIG_ISA
-	case SNDRV_PCM_DMA_TYPE_ISA:
-		dmab->area = snd_malloc_isa_pages(size, &dmab->addr);
-		break;
-#endif
-#ifdef CONFIG_PCI
-	case SNDRV_PCM_DMA_TYPE_PCI:
-		dmab->area = snd_malloc_pci_pages((struct pci_dev *)substream->dma_private, size, &dmab->addr);
-		break;
-	case SNDRV_PCM_DMA_TYPE_PCI_SG:
-		snd_pcm_sgbuf_alloc_pages((struct pci_dev *)substream->dma_private, size, dmab);
-		break;
-#endif
-#ifdef CONFIG_SBUS
-	case SNDRV_PCM_DMA_TYPE_SBUS:
-		dmab->area = snd_malloc_sbus_pages((struct sbus_dev *)substream->dma_private, size, &dmab->addr);
-		break;
-#endif
-	default:
-		dmab->area = NULL;
-		dmab->addr = 0;
-		return -ENXIO;
-	}
-	return 0;
-}
-
-/*
  * try to allocate as the large pages as possible.
  * stores the resultant memory size in *res_size.
  *
  * the minimum size is snd_minimum_buffer.  it should be power of 2.
  */
-static int alloc_pcm_pages_fallback(snd_pcm_substream_t *substream,
-				    size_t size,
-				    struct snd_pcm_dma_buffer *dmab)
+static int preallocate_pcm_pages(snd_pcm_substream_t *substream, size_t size)
 {
+	struct snd_dma_buffer *dmab = &substream->dma_buffer;
 	int err;
+
 	snd_assert(size > 0, return -EINVAL);
+
+	/* already reserved? */
+	if (snd_dma_get_reserved(&substream->dma_device, dmab) > 0) {
+		if (dmab->bytes >= size)
+			return 0; /* yes */
+		/* no, reset the reserved block */
+		snd_dma_free_reserved(&substream->dma_device);
+		dmab->bytes = 0;
+	}
+
 	do {
-		if ((err = alloc_pcm_pages(substream, size, dmab)) < 0)
+		if ((err = snd_dma_alloc_pages(&substream->dma_device, size, dmab)) < 0)
 			return err;
 		if (dmab->area) {
-			dmab->bytes = size;
+			/* remember this one */
+			snd_dma_set_reserved(&substream->dma_device, dmab);
 			return 0;
 		}
 		size >>= 1;
@@ -106,46 +77,13 @@
 }
 
 /*
- * release the pages on the specified bus
- */
-static void free_pcm_pages(snd_pcm_substream_t *substream,
-			   struct snd_pcm_dma_buffer *dmab)
-{
-	switch (substream->dma_type) {
-	case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
-		snd_free_pages(dmab->area, dmab->bytes);
-		break;
-#ifdef CONFIG_ISA
-	case SNDRV_PCM_DMA_TYPE_ISA:
-		snd_free_isa_pages(dmab->bytes, dmab->area, dmab->addr);
-		break;
-#endif
-#ifdef CONFIG_PCI
-	case SNDRV_PCM_DMA_TYPE_PCI:
-		snd_free_pci_pages((struct pci_dev *)substream->dma_private,
-				   dmab->bytes, dmab->area, dmab->addr);
-		break;
-	case SNDRV_PCM_DMA_TYPE_PCI_SG:
-		snd_pcm_sgbuf_free_pages(dmab);
-		break;
-#endif
-#ifdef CONFIG_SBUS
-	case SNDRV_PCM_DMA_TYPE_SBUS:
-		snd_free_sbus_pages((struct sbus_dev *)substream->dma_private,
-				    dmab->bytes, dmab->area, dmab->addr);
-		break;
-#endif
-	}
-}
-
-/*
  * release the preallocated buffer if not yet done.
  */
 static void snd_pcm_lib_preallocate_dma_free(snd_pcm_substream_t *substream)
 {
 	if (substream->dma_buffer.area == NULL)
 		return;
-	free_pcm_pages(substream, &substream->dma_buffer);
+	snd_dma_free_reserved(&substream->dma_device);
 	substream->dma_buffer.area = NULL;
 }
 
@@ -164,7 +102,7 @@
 		snd_info_unregister(substream->proc_prealloc_entry);
 		substream->proc_prealloc_entry = NULL;
 	}
-	substream->dma_type = SNDRV_PCM_DMA_TYPE_UNKNOWN;
+	substream->dma_device.type = SNDRV_DMA_TYPE_UNKNOWN;
 	return 0;
 }
 
@@ -210,7 +148,7 @@
 	snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
 	char line[64], str[64];
 	size_t size;
-	struct snd_pcm_dma_buffer new_dmab;
+	struct snd_dma_buffer new_dmab;
 
 	if (substream->runtime) {
 		buffer->error = -EBUSY;
@@ -228,7 +166,7 @@
 		memset(&new_dmab, 0, sizeof(new_dmab));
 		if (size > 0) {
 
-			if (alloc_pcm_pages(substream, size, &new_dmab) < 0 ||
+			if (snd_dma_alloc_pages(&substream->dma_device, size, &new_dmab) < 0 ||
 			    new_dmab.area == NULL) {
 				buffer->error = -ENOMEM;
 				return;
@@ -237,7 +175,7 @@
 		} else {
 			substream->buffer_bytes_max = UINT_MAX;
 		}
-		snd_pcm_lib_preallocate_dma_free(substream);
+		snd_dma_set_reserved(&substream->dma_device, &new_dmab);
 		substream->dma_buffer = new_dmab;
 	} else {
 		buffer->error = -EINVAL;
@@ -254,7 +192,7 @@
 
 	memset(&substream->dma_buffer, 0, sizeof(substream->dma_buffer));
 	if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
-		alloc_pcm_pages_fallback(substream, size, &substream->dma_buffer);
+		preallocate_pcm_pages(substream, size);
 
 	if (substream->dma_buffer.bytes > 0)
 		substream->buffer_bytes_max = substream->dma_buffer.bytes;
@@ -274,6 +212,16 @@
 	return 0;
 }
 
+
+/*
+ * set up the unique pcm id
+ */
+static inline void setup_pcm_id(snd_pcm_substream_t *subs)
+{
+	subs->dma_device.id = subs->pcm->device << 16 |
+		subs->stream << 8 | subs->number;
+}
+
 /**
  * snd_pcm_lib_preallocate_pages - pre-allocation for the continuous memory type
  * @substream: the pcm substream instance
@@ -289,8 +237,9 @@
 				      size_t size, size_t max,
 				      unsigned int flags)
 {
-	substream->dma_type = SNDRV_PCM_DMA_TYPE_CONTINUOUS;
-	substream->dma_private = (void *)(unsigned long)flags;
+	substream->dma_device.type = SNDRV_DMA_TYPE_CONTINUOUS;
+	substream->dma_device.dev.flags = flags;
+	setup_pcm_id(substream);
 	return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -334,8 +283,9 @@
 int snd_pcm_lib_preallocate_isa_pages(snd_pcm_substream_t *substream,
 				      size_t size, size_t max)
 {
-	substream->dma_type = SNDRV_PCM_DMA_TYPE_ISA;
-	substream->dma_private = NULL;
+	substream->dma_device.type = SNDRV_DMA_TYPE_ISA;
+	substream->dma_device.dev.flags = 0; /* FIXME: any good identifier? */
+	setup_pcm_id(substream);
 	return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -379,9 +329,9 @@
 int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size)
 {
 	snd_pcm_runtime_t *runtime;
-	struct snd_pcm_dma_buffer dmab;
+	struct snd_dma_buffer dmab;
 
-	snd_assert(substream->dma_type != SNDRV_PCM_DMA_TYPE_UNKNOWN, return -EINVAL);
+	snd_assert(substream->dma_device.type != SNDRV_DMA_TYPE_UNKNOWN, return -EINVAL);
 	snd_assert(substream != NULL, return -EINVAL);
 	runtime = substream->runtime;
 	snd_assert(runtime != NULL, return -EINVAL);	
@@ -398,7 +348,7 @@
 		dmab = substream->dma_buffer;
 	} else {
 		memset(&dmab, 0, sizeof(dmab));
-		alloc_pcm_pages(substream, size, &dmab);
+		snd_dma_alloc_pages(&substream->dma_device, size, &dmab);
 	}
 	if (! dmab.area)
 		return -ENOMEM;
@@ -427,13 +377,13 @@
 	if (runtime->dma_area == NULL)
 		return 0;
 	if (runtime->dma_area != substream->dma_buffer.area) {
-		struct snd_pcm_dma_buffer dmab;
+		struct snd_dma_buffer dmab;
 		memset(&dmab, 0, sizeof(dmab));
 		dmab.area = runtime->dma_area;
 		dmab.addr = runtime->dma_addr;
 		dmab.bytes = runtime->dma_bytes;
 		dmab.private_data = runtime->dma_private;
-		free_pcm_pages(substream, &dmab);
+		snd_dma_free_pages(&substream->dma_device, &dmab);
 	}
 	runtime->dma_area = NULL;
 	runtime->dma_addr = 0UL;
@@ -459,8 +409,9 @@
 				      snd_pcm_substream_t *substream,
 				      size_t size, size_t max)
 {
-	substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI;
-	substream->dma_private = pci;
+	substream->dma_device.type = SNDRV_DMA_TYPE_PCI;
+	substream->dma_device.dev.pci = pci;
+	setup_pcm_id(substream);
 	return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -510,8 +461,9 @@
 				       snd_pcm_substream_t *substream,
 				       size_t size, size_t max)
 {
-	substream->dma_type = SNDRV_PCM_DMA_TYPE_SBUS;
-	substream->dma_private = sdev;
+	substream->dma_device.type = SNDRV_DMA_TYPE_SBUS;
+	substream->dma_device.dev.sbus = sdev;
+	setup_pcm_id(substream);
 	return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -563,8 +515,9 @@
 				     snd_pcm_substream_t *substream,
 				     size_t size, size_t max)
 {
-	substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI_SG;
-	substream->dma_private = pci;
+	substream->dma_device.type = SNDRV_DMA_TYPE_PCI_SG;
+	substream->dma_device.dev.pci = pci;
+	setup_pcm_id(substream);
 	return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -596,4 +549,22 @@
 	return 0;
 }
 
+/**
+ * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
+ * @substream: the pcm substream instance
+ * @offset: the buffer offset
+ *
+ * Returns the page struct at the given buffer offset.
+ * Used as the page callback of PCM ops.
+ */
+struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
+{
+	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+
+	unsigned int idx = offset >> PAGE_SHIFT;
+	if (idx >= (unsigned int)sgbuf->pages)
+		return NULL;
+	return sgbuf->page_table[idx];
+}
+
 #endif /* CONFIG_PCI */
diff -urN linux-2.5.65-bk1/sound/core/pcm_misc.c linux-2.5.65-bk2/sound/core/pcm_misc.c
--- linux-2.5.65-bk1/sound/core/pcm_misc.c	Mon Mar 17 13:44:38 2003
+++ linux-2.5.65-bk2/sound/core/pcm_misc.c	Mon Mar 31 12:39:51 2003
@@ -527,7 +527,7 @@
  *
  * Sets the silence data on the buffer for the given samples.
  *
- * Returns zero if sucessful, or a negative error code on failure.
+ * Returns zero if successful, or a negative error code on failure.
  */
 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
 {
diff -urN linux-2.5.65-bk1/sound/core/pcm_native.c linux-2.5.65-bk2/sound/core/pcm_native.c
--- linux-2.5.65-bk1/sound/core/pcm_native.c	Mon Mar 17 13:44:02 2003
+++ linux-2.5.65-bk2/sound/core/pcm_native.c	Mon Mar 31 12:39:51 2003
@@ -30,6 +30,7 @@
 #include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/timer.h>
 #include <sound/minors.h>
 
 /*
@@ -514,9 +515,9 @@
 		if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
 			status->tstamp = runtime->status->tstamp;
 		else
-			snd_timestamp_now(&status->tstamp);
+			snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec);
 	} else
-		snd_timestamp_now(&status->tstamp);
+		snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec);
 	status->appl_ptr = runtime->control->appl_ptr;
 	status->hw_ptr = runtime->status->hw_ptr;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -585,15 +586,15 @@
 	return 0;
 }
 
-static void snd_pcm_trigger_time(snd_pcm_substream_t *substream)
+static void snd_pcm_trigger_tstamp(snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	if (runtime->trigger_master == NULL)
 		return;
 	if (runtime->trigger_master == substream) {
-		snd_timestamp_now(&runtime->trigger_tstamp);
+		snd_timestamp_now(&runtime->trigger_tstamp, runtime->tstamp_timespec);
 	} else {
-		snd_pcm_trigger_time(runtime->trigger_master);
+		snd_pcm_trigger_tstamp(runtime->trigger_master);
 		runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
 	}
 	runtime->trigger_master = NULL;
@@ -668,13 +669,15 @@
 static inline void snd_pcm_post_start(snd_pcm_substream_t *substream, int state)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_pcm_trigger_time(substream);
+	snd_pcm_trigger_tstamp(substream);
 	runtime->status->state = SNDRV_PCM_STATE_RUNNING;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
 		snd_pcm_playback_silence(substream, ULONG_MAX);
 	if (runtime->sleep_min)
 		snd_pcm_tick_prepare(substream);
+	if (substream->timer)
+		snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, &runtime->trigger_tstamp);
 }
 
 /**
@@ -703,7 +706,9 @@
 static inline void snd_pcm_post_stop(snd_pcm_substream_t *substream, int state)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_pcm_trigger_time(substream);
+	snd_pcm_trigger_tstamp(substream);
+	if (substream->timer)
+		snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, &runtime->trigger_tstamp);
 	runtime->status->state = state;
 	snd_pcm_tick_set(substream, 0);
 	wake_up(&runtime->sleep);
@@ -741,15 +746,19 @@
 static inline void snd_pcm_post_pause(snd_pcm_substream_t *substream, int push)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_pcm_trigger_time(substream);
+	snd_pcm_trigger_tstamp(substream);
 	if (push) {
 		runtime->status->state = SNDRV_PCM_STATE_PAUSED;
+		if (substream->timer)
+			snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
 		snd_pcm_tick_set(substream, 0);
 		wake_up(&runtime->sleep);
 	} else {
 		runtime->status->state = SNDRV_PCM_STATE_RUNNING;
 		if (runtime->sleep_min)
 			snd_pcm_tick_prepare(substream);
+		if (substream->timer)
+			snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
 	}
 }
 
@@ -782,7 +791,9 @@
 static inline void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_pcm_trigger_time(substream);
+	snd_pcm_trigger_tstamp(substream);
+	if (substream->timer)
+		snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
 	runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
 	snd_pcm_tick_set(substream, 0);
 	wake_up(&runtime->sleep);
@@ -847,7 +858,9 @@
 static inline void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_pcm_trigger_time(substream);
+	snd_pcm_trigger_tstamp(substream);
+	if (substream->timer)
+		snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
 	runtime->status->state = runtime->status->suspended_state;
 	if (runtime->sleep_min)
 		snd_pcm_tick_prepare(substream);
@@ -1733,9 +1746,12 @@
 	runtime = substream->runtime;
 	str = substream->pstr;
 	snd_pcm_unlink(substream);
-	if (substream->ops->hw_free != NULL)
-		substream->ops->hw_free(substream);
-	substream->ops->close(substream);
+	if (substream->open_flag) {
+		if (substream->ops->hw_free != NULL)
+			substream->ops->hw_free(substream);
+		substream->ops->close(substream);
+		substream->open_flag = 0;
+	}
 	substream->ffile = NULL;
 	snd_pcm_remove_file(str, pcm_file);
 	snd_pcm_release_substream(substream);
@@ -1784,6 +1800,7 @@
 		snd_pcm_release_file(pcm_file);
 		return err;
 	}
+	substream->open_flag = 1;
 
 	err = snd_pcm_hw_constraints_complete(substream);
 	if (err < 0) {
@@ -1982,6 +1999,106 @@
 	return ret;
 }
 
+snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_sframes_t appl_ptr;
+	snd_pcm_sframes_t ret;
+	snd_pcm_sframes_t avail;
+
+	if (frames == 0)
+		return 0;
+
+	spin_lock_irq(&runtime->lock);
+	switch (runtime->status->state) {
+	case SNDRV_PCM_STATE_PREPARED:
+	case SNDRV_PCM_STATE_PAUSED:
+		break;
+	case SNDRV_PCM_STATE_DRAINING:
+	case SNDRV_PCM_STATE_RUNNING:
+		if (snd_pcm_update_hw_ptr(substream) >= 0)
+			break;
+		/* Fall through */
+	case SNDRV_PCM_STATE_XRUN:
+		ret = -EPIPE;
+		goto __end;
+	default:
+		ret = -EBADFD;
+		goto __end;
+	}
+
+	avail = snd_pcm_playback_avail(runtime);
+	if (avail <= 0) {
+		ret = 0;
+		goto __end;
+	}
+	if (frames > (snd_pcm_uframes_t)avail)
+		frames = avail;
+	else
+		frames -= frames % runtime->xfer_align;
+	appl_ptr = runtime->control->appl_ptr + frames;
+	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
+		appl_ptr -= runtime->boundary;
+	runtime->control->appl_ptr = appl_ptr;
+	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
+	    runtime->sleep_min)
+		snd_pcm_tick_prepare(substream);
+	ret = frames;
+ __end:
+	spin_unlock_irq(&runtime->lock);
+	return ret;
+}
+
+snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_sframes_t appl_ptr;
+	snd_pcm_sframes_t ret;
+	snd_pcm_sframes_t avail;
+
+	if (frames == 0)
+		return 0;
+
+	spin_lock_irq(&runtime->lock);
+	switch (runtime->status->state) {
+	case SNDRV_PCM_STATE_PREPARED:
+	case SNDRV_PCM_STATE_DRAINING:
+	case SNDRV_PCM_STATE_PAUSED:
+		break;
+	case SNDRV_PCM_STATE_RUNNING:
+		if (snd_pcm_update_hw_ptr(substream) >= 0)
+			break;
+		/* Fall through */
+	case SNDRV_PCM_STATE_XRUN:
+		ret = -EPIPE;
+		goto __end;
+	default:
+		ret = -EBADFD;
+		goto __end;
+	}
+
+	avail = snd_pcm_capture_avail(runtime);
+	if (avail <= 0) {
+		ret = 0;
+		goto __end;
+	}
+	if (frames > (snd_pcm_uframes_t)avail)
+		frames = avail;
+	else
+		frames -= frames % runtime->xfer_align;
+	appl_ptr = runtime->control->appl_ptr + frames;
+	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
+		appl_ptr -= runtime->boundary;
+	runtime->control->appl_ptr = appl_ptr;
+	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
+	    runtime->sleep_min)
+		snd_pcm_tick_prepare(substream);
+	ret = frames;
+ __end:
+	spin_unlock_irq(&runtime->lock);
+	return ret;
+}
+
 static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
@@ -2065,6 +2182,14 @@
 		return put_user(SNDRV_PCM_VERSION, (int *)arg) ? -EFAULT : 0;
 	case SNDRV_PCM_IOCTL_INFO:
 		return snd_pcm_info_user(substream, (snd_pcm_info_t *) arg);
+	case SNDRV_PCM_IOCTL_TSTAMP:
+	{
+		int xarg;
+		if (get_user(xarg, (int *) arg))
+			return -EFAULT;
+		substream->runtime->tstamp_timespec = xarg ? 1 : 0;
+		return 0;
+	}
 	case SNDRV_PCM_IOCTL_HW_REFINE:
 		return snd_pcm_hw_refine_user(substream, (snd_pcm_hw_params_t *) arg);
 	case SNDRV_PCM_IOCTL_HW_PARAMS:
@@ -2169,6 +2294,18 @@
 		__put_user(result, _frames);
 		return result < 0 ? result : 0;
 	}
+	case SNDRV_PCM_IOCTL_FORWARD:
+	{
+		snd_pcm_uframes_t frames, *_frames = arg;
+		snd_pcm_sframes_t result;
+		if (get_user(frames, _frames))
+			return -EFAULT;
+		if (put_user(0, _frames))
+			return -EFAULT;
+		result = snd_pcm_playback_forward(substream, frames);
+		__put_user(result, _frames);
+		return result < 0 ? result : 0;
+	}
 	case SNDRV_PCM_IOCTL_PAUSE:
 	{
 		int res;
@@ -2244,6 +2381,18 @@
 		__put_user(result, _frames);
 		return result < 0 ? result : 0;
 	}
+	case SNDRV_PCM_IOCTL_FORWARD:
+	{
+		snd_pcm_uframes_t frames, *_frames = arg;
+		snd_pcm_sframes_t result;
+		if (get_user(frames, _frames))
+			return -EFAULT;
+		if (put_user(0, _frames))
+			return -EFAULT;
+		result = snd_pcm_capture_forward(substream, frames);
+		__put_user(result, _frames);
+		return result < 0 ? result : 0;
+	}
 	case SNDRV_PCM_IOCTL_DRAIN:
 		return snd_pcm_capture_drain(substream);
 	case SNDRV_PCM_IOCTL_DROP:
diff -urN linux-2.5.65-bk1/sound/core/pcm_sgbuf.c linux-2.5.65-bk2/sound/core/pcm_sgbuf.c
--- linux-2.5.65-bk1/sound/core/pcm_sgbuf.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/sound/core/pcm_sgbuf.c	Wed Dec 31 16:00:00 1969
@@ -1,149 +0,0 @@
-/*
- * Scatter-Gather PCM access
- *
- *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <sound/driver.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_sgbuf.h>
-
-
-/* table entries are align to 32 */
-#define SGBUF_TBL_ALIGN		32
-#define sgbuf_align_table(tbl)	((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
-
-
-/**
- * snd_pcm_sgbuf_alloc_pages - allocate the pages for the SG buffer
- * @pci: the pci device pointer
- * @size: the requested buffer size in bytes
- * @dmab: the dma-buffer record to store
- *
- * Initializes the SG-buffer table and allocates the buffer pages
- * for the given size.
- * The pages are mapped to the virtually continuous memory.
- *
- * This function is usually called from snd_pcm_lib_malloc_pages().
- *
- * Returns the mapped virtual address of the buffer if allocation was
- * successful, or NULL at error.
- */
-void *snd_pcm_sgbuf_alloc_pages(struct pci_dev *pci, size_t size, struct snd_pcm_dma_buffer *dmab)
-{
-	struct snd_sg_buf *sgbuf;
-	unsigned int i, pages;
-
-	dmab->area = NULL;
-	dmab->addr = 0;
-	dmab->private_data = sgbuf = snd_magic_kcalloc(snd_pcm_sgbuf_t, 0, GFP_KERNEL);
-	if (! sgbuf)
-		return NULL;
-	sgbuf->pci = pci;
-	pages = snd_pcm_sgbuf_pages(size);
-	sgbuf->tblsize = sgbuf_align_table(pages);
-	sgbuf->table = snd_kcalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL);
-	if (! sgbuf->table)
-		goto _failed;
-	sgbuf->page_table = snd_kcalloc(sizeof(*sgbuf->page_table) * sgbuf->tblsize, GFP_KERNEL);
-	if (! sgbuf->page_table)
-		goto _failed;
-
-	/* allocate each page */
-	for (i = 0; i < pages; i++) {
-		void *ptr;
-		dma_addr_t addr;
-		ptr = snd_malloc_pci_page(sgbuf->pci, &addr);
-		if (! ptr)
-			goto _failed;
-		sgbuf->table[i].buf = ptr;
-		sgbuf->table[i].addr = addr;
-		sgbuf->page_table[i] = virt_to_page(ptr);
-		sgbuf->pages++;
-	}
-
-	sgbuf->size = size;
-	dmab->area = vmap(sgbuf->page_table, sgbuf->pages);
-	if (! dmab->area)
-		goto _failed;
-	return dmab->area;
-
- _failed:
-	snd_pcm_sgbuf_free_pages(dmab); /* free the table */
-	return NULL;
-}
-
-/**
- * snd_pcm_sgbuf_free_pages - free the sg buffer
- * @dmab: dma buffer record
- *
- * Releases the pages and the SG-buffer table.
- *
- * This function is called usually from snd_pcm_lib_free_pages().
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_sgbuf_free_pages(struct snd_pcm_dma_buffer *dmab)
-{
-	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, dmab->private_data, return -EINVAL);
-	int i;
-
-	for (i = 0; i < sgbuf->pages; i++)
-		snd_free_pci_page(sgbuf->pci, sgbuf->table[i].buf, sgbuf->table[i].addr);
-	if (dmab->area)
-		vunmap(dmab->area);
-	dmab->area = NULL;
-
-	if (sgbuf->table)
-		kfree(sgbuf->table);
-	if (sgbuf->page_table)
-		kfree(sgbuf->page_table);
-	snd_magic_kfree(sgbuf);
-	dmab->private_data = NULL;
-	
-	return 0;
-}
-
-/**
- * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
- * @substream: the pcm substream instance
- * @offset: the buffer offset
- *
- * Returns the page struct at the given buffer offset.
- * Used as the page callback of PCM ops.
- */
-struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
-{
-	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, _snd_pcm_substream_sgbuf(substream), return NULL);
-
-	unsigned int idx = offset >> PAGE_SHIFT;
-	if (idx >= (unsigned int)sgbuf->pages)
-		return NULL;
-	return sgbuf->page_table[idx];
-}
-
-
-/*
- *  Exported symbols
- */
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages_for_all);
-EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
diff -urN linux-2.5.65-bk1/sound/core/rawmidi.c linux-2.5.65-bk2/sound/core/rawmidi.c
--- linux-2.5.65-bk1/sound/core/rawmidi.c	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/sound/core/rawmidi.c	Mon Mar 31 12:39:51 2003
@@ -79,7 +79,8 @@
 static inline int snd_rawmidi_ready_append(snd_rawmidi_substream_t * substream, size_t count)
 {
 	snd_rawmidi_runtime_t *runtime = substream->runtime;
-	return runtime->avail >= runtime->avail_min && runtime->avail >= count;
+	return runtime->avail >= runtime->avail_min &&
+	       (!substream->append || runtime->avail >= count);
 }
 
 static int snd_rawmidi_init(snd_rawmidi_substream_t *substream)
diff -urN linux-2.5.65-bk1/sound/core/seq/oss/seq_oss_init.c linux-2.5.65-bk2/sound/core/seq/oss/seq_oss_init.c
--- linux-2.5.65-bk1/sound/core/seq/oss/seq_oss_init.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/sound/core/seq/oss/seq_oss_init.c	Mon Mar 31 12:39:51 2003
@@ -51,7 +51,7 @@
 static int create_port(seq_oss_devinfo_t *dp);
 static int delete_port(seq_oss_devinfo_t *dp);
 static int alloc_seq_queue(seq_oss_devinfo_t *dp);
-static int delete_seq_queue(seq_oss_devinfo_t *dp);
+static int delete_seq_queue(int queue);
 static void free_devinfo(void *private);
 
 #define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec)
@@ -186,6 +186,7 @@
 		snd_printk(KERN_ERR "can't malloc device info\n");
 		return -ENOMEM;
 	}
+	debug_printk(("oss_open: dp = %p\n", dp));
 
 	for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) {
 		if (client_table[i] == NULL)
@@ -193,6 +194,7 @@
 	}
 	if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
 		snd_printk(KERN_ERR "too many applications\n");
+		kfree(dp);
 		return -ENOMEM;
 	}
 
@@ -209,22 +211,21 @@
 
 	if (dp->synth_opened == 0 && dp->max_mididev == 0) {
 		snd_printk(KERN_ERR "no device found\n");
-		kfree(dp);
-		return -ENODEV;
+		rc = -ENODEV;
+		goto _error;
 	}
 
 	/* create port */
+	debug_printk(("create new port\n"));
 	if ((rc = create_port(dp)) < 0) {
 		snd_printk(KERN_ERR "can't create port\n");
-		free_devinfo(dp);
-		return rc;
+		goto _error;
 	}
 
 	/* allocate queue */
-	if ((rc = alloc_seq_queue(dp)) < 0) {
-		delete_port(dp);
-		return rc;
-	}
+	debug_printk(("allocate queue\n"));
+	if ((rc = alloc_seq_queue(dp)) < 0)
+		goto _error;
 
 	/* set address */
 	dp->addr.client = dp->cseq;
@@ -238,31 +239,32 @@
 	dp->file_mode = translate_mode(file);
 
 	/* initialize read queue */
+	debug_printk(("initialize read queue\n"));
 	if (is_read_mode(dp->file_mode)) {
 		if ((dp->readq = snd_seq_oss_readq_new(dp, maxqlen)) == NULL) {
-			delete_seq_queue(dp);
-			delete_port(dp);
-			return -ENOMEM;
+			rc = -ENOMEM;
+			goto _error;
 		}
 	}
 
 	/* initialize write queue */
+	debug_printk(("initialize write queue\n"));
 	if (is_write_mode(dp->file_mode)) {
 		dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
 		if (dp->writeq == NULL) {
-			delete_seq_queue(dp);
-			delete_port(dp);
-			return -ENOMEM;
+			rc = -ENOMEM;
+			goto _error;
 		}
 	}
 
 	/* initialize timer */
+	debug_printk(("initialize timer\n"));
 	if ((dp->timer = snd_seq_oss_timer_new(dp)) == NULL) {
 		snd_printk(KERN_ERR "can't alloc timer\n");
-		delete_seq_queue(dp);
-		delete_port(dp);
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto _error;
 	}
+	debug_printk(("timer initialized\n"));
 
 	/* set private data pointer */
 	file->private_data = dp;
@@ -277,8 +279,16 @@
 	num_clients++;
 
 	debug_printk(("open done\n"));
-
 	return 0;
+
+ _error:
+	snd_seq_oss_synth_cleanup(dp);
+	snd_seq_oss_midi_cleanup(dp);
+	i = dp->queue;
+	delete_port(dp);
+	delete_seq_queue(i);
+
+	return rc;
 }
 
 /*
@@ -344,6 +354,7 @@
 	if (dp->port < 0)
 		return 0;
 
+	debug_printk(("delete_port %i\n", dp->port));
 	memset(&port_info, 0, sizeof(port_info));
 	port_info.addr.client = dp->cseq;
 	port_info.addr.port = dp->port;
@@ -375,15 +386,19 @@
  * release queue
  */
 static int
-delete_seq_queue(seq_oss_devinfo_t *dp)
+delete_seq_queue(int queue)
 {
 	snd_seq_queue_info_t qinfo;
+	int rc;
 
-	if (dp->queue < 0)
+	if (queue < 0)
 		return 0;
 	memset(&qinfo, 0, sizeof(qinfo));
-	qinfo.queue = dp->queue;
-	return call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
+	qinfo.queue = queue;
+	rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
+	if (rc < 0)
+		printk(KERN_ERR "seq-oss: unable to delete queue %d (%d)\n", queue, rc);
+	return rc;
 }
 
 
@@ -414,6 +429,8 @@
 void
 snd_seq_oss_release(seq_oss_devinfo_t *dp)
 {
+	int queue;
+
 	client_table[dp->index] = NULL;
 	num_clients--;
 
@@ -426,10 +443,10 @@
 
 	/* clear slot */
 	debug_printk(("releasing resource..\n"));
+	queue = dp->queue;
 	if (dp->port >= 0)
 		delete_port(dp);
-	if (dp->queue >= 0)
-		delete_seq_queue(dp);
+	delete_seq_queue(queue);
 
 	debug_printk(("release done\n"));
 }
diff -urN linux-2.5.65-bk1/sound/core/seq/oss/seq_oss_midi.c linux-2.5.65-bk2/sound/core/seq/oss/seq_oss_midi.c
--- linux-2.5.65-bk1/sound/core/seq/oss/seq_oss_midi.c	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/sound/core/seq/oss/seq_oss_midi.c	Mon Mar 31 12:39:51 2003
@@ -206,9 +206,9 @@
 	}
 	if (i >= max_midi_devs) {
 		if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) {
+			spin_unlock_irqrestore(&register_lock, flags);
 			snd_midi_event_free(mdev->coder);
 			kfree(mdev);
-			spin_unlock_irqrestore(&register_lock, flags);
 			return -ENOMEM;
 		}
 		max_midi_devs++;
@@ -372,6 +372,8 @@
 		subs.sender.client = mdev->client;
 		subs.sender.port = mdev->port;
 		subs.dest = dp->addr;
+		subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP;
+		subs.queue = dp->queue;		/* queue for timestamps */
 		if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
 			mdev->opened |= PERM_READ;
 	}
@@ -462,8 +464,7 @@
 		return;
 	}
 
-	if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC &&
-	    (mdev->opened & PERM_WRITE)) {
+	if (mdev->opened & PERM_WRITE) {
 		snd_seq_event_t ev;
 		int c;
 
@@ -473,16 +474,22 @@
 		ev.dest.port = mdev->port;
 		ev.queue = dp->queue;
 		ev.source.port = dp->port;
+		if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) {
+			ev.type = SNDRV_SEQ_EVENT_SENSING;
+			snd_seq_oss_dispatch(dp, &ev, 0, 0); /* active sensing */
+		}
 		for (c = 0; c < 16; c++) {
 			ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
 			ev.data.control.channel = c;
 			ev.data.control.param = 123;
 			snd_seq_oss_dispatch(dp, &ev, 0, 0); /* all notes off */
-			ev.data.control.param = 121;
-			snd_seq_oss_dispatch(dp, &ev, 0, 0); /* reset all controllers */
-			ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
-			ev.data.control.value = 0;
-			snd_seq_oss_dispatch(dp, &ev, 0, 0); /* bender off */
+			if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
+				ev.data.control.param = 121;
+				snd_seq_oss_dispatch(dp, &ev, 0, 0); /* reset all controllers */
+				ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
+				ev.data.control.value = 0;
+				snd_seq_oss_dispatch(dp, &ev, 0, 0); /* bender off */
+			}
 		}
 	}
 	snd_seq_oss_midi_close(dp, dev);
@@ -597,10 +604,12 @@
 static int
 send_midi_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, seq_oss_midi_t *mdev)
 {
-	char msg[32]; /* enough except for sysex? */
+	char msg[32];
 	int len;
 	
-	snd_seq_oss_readq_put_timestamp(dp->readq, snd_seq_oss_timer_cur_tick(dp->timer), dp->seq_mode);
+	snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
+	if (!dp->timer->running)
+		len = snd_seq_oss_timer_start(dp->timer);
 	if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
 		if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
 			snd_seq_oss_readq_puts(dp->readq, mdev->seq_device,
diff -urN linux-2.5.65-bk1/sound/core/seq/oss/seq_oss_synth.c linux-2.5.65-bk2/sound/core/seq/oss/seq_oss_synth.c
--- linux-2.5.65-bk1/sound/core/seq/oss/seq_oss_synth.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/sound/core/seq/oss/seq_oss_synth.c	Mon Mar 31 12:39:51 2003
@@ -302,29 +302,36 @@
 	seq_oss_synth_t *rec;
 	seq_oss_synthinfo_t *info;
 
+	snd_assert(dp->max_synthdev <= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS, return);
 	for (i = 0; i < dp->max_synthdev; i++) {
 		info = &dp->synths[i];
 		if (! info->opened)
 			continue;
 		if (info->is_midi) {
-			snd_seq_oss_midi_close(dp, info->midi_mapped);
-			midi_synth_dev.opened--;
+			if (midi_synth_dev.opened > 0) {
+				snd_seq_oss_midi_close(dp, info->midi_mapped);
+				midi_synth_dev.opened--;
+			}
 		} else {
 			rec = get_sdev(i);
 			if (rec == NULL)
 				continue;
-			if (rec->opened) {
+			if (rec->opened > 0) {
 				debug_printk(("synth %d closed\n", i));
 				rec->oper.close(&info->arg);
 				module_put(rec->oper.owner);
-				rec->opened--;
+				rec->opened = 0;
 			}
 			snd_use_lock_free(&rec->use_lock);
 		}
-		if (info->sysex)
+		if (info->sysex) {
 			kfree(info->sysex);
-		if (info->ch)
+			info->sysex = NULL;
+		}
+		if (info->ch) {
 			kfree(info->ch);
+			info->ch = NULL;
+		}
 	}
 	dp->synth_opened = 0;
 	dp->max_synthdev = 0;
@@ -401,15 +408,21 @@
 		info->sysex->len = 0; /* reset sysex */
 	reset_channels(info);
 	if (info->is_midi) {
+		if (midi_synth_dev.opened <= 0)
+			return;
 		snd_seq_oss_midi_reset(dp, info->midi_mapped);
 		if (snd_seq_oss_midi_open(dp, info->midi_mapped,
 					  dp->file_mode) < 0) {
 			midi_synth_dev.opened--;
 			info->opened = 0;
-			if (info->sysex)
+			if (info->sysex) {
 				kfree(info->sysex);
-			if (info->ch)
+				info->sysex = NULL;
+			}
+			if (info->ch) {
 				kfree(info->ch);
+				info->ch = NULL;
+			}
 		}
 		return;
 	}
diff -urN linux-2.5.65-bk1/sound/core/seq/seq_midi.c linux-2.5.65-bk2/sound/core/seq/seq_midi.c
--- linux-2.5.65-bk1/sound/core/seq/seq_midi.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/sound/core/seq/seq_midi.c	Mon Mar 31 12:39:51 2003
@@ -272,6 +272,21 @@
 		snd_midi_event_free(msynth->parser);
 }
 
+/* set our client name */
+static int set_client_name(seq_midisynth_client_t *client, snd_card_t *card,
+			   snd_rawmidi_info_t *rmidi)
+{
+	snd_seq_client_info_t cinfo;
+	const char *name;
+
+	memset(&cinfo, 0, sizeof(cinfo));
+	cinfo.client = client->seq_client;
+	cinfo.type = KERNEL_CLIENT;
+	name = rmidi->name[0] ? (const char *)rmidi->name : "External MIDI";
+	snprintf(cinfo.name, sizeof(cinfo.name), "Rawmidi %d - %s", card->number, name);
+	return snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
+}
+
 /* register new midi synth port */
 int
 snd_seq_midisynth_register_port(snd_seq_device_t *dev)
@@ -284,7 +299,6 @@
 	unsigned int p, ports;
 	snd_seq_client_callback_t callbacks;
 	snd_seq_port_callback_t pcallbacks;
-	snd_seq_client_info_t inf;
 	snd_card_t *card = dev->card;
 	int device = dev->device;
 	unsigned int input_count = 0, output_count = 0;
@@ -325,13 +339,9 @@
 			up(&register_mutex);
 			return -ENOMEM;
 		}
-		/* set our client name */
-		memset(&inf,0,sizeof(snd_seq_client_info_t));
-		inf.client = client->seq_client;
-		inf.type = KERNEL_CLIENT;
-		sprintf(inf.name, "External MIDI %i", card->number);
-		snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &inf);
-	}
+		set_client_name(client, card, &info);
+	} else if (device == 0)
+		set_client_name(client, card, &info); /* use the first device's name */
 
 	msynth = snd_kcalloc(sizeof(seq_midisynth_t) * ports, GFP_KERNEL);
 	if (msynth == NULL)
@@ -358,10 +368,18 @@
 		if (snd_rawmidi_info_select(card, &info) >= 0)
 			strcpy(port.name, info.subname);
 		if (! port.name[0]) {
-			if (ports > 1)
-				sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
-			else
-				sprintf(port.name, "MIDI %d-%d", card->number, device);
+			if (info.name[0]) {
+				if (ports > 1)
+					snprintf(port.name, sizeof(port.name), "%s-%d", info.name, p);
+				else
+					snprintf(port.name, sizeof(port.name), "%s", info.name);
+			} else {
+				/* last resort */
+				if (ports > 1)
+					sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
+				else
+					sprintf(port.name, "MIDI %d-%d", card->number, device);
+			}
 		}
 		if ((info.flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
 			port.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
diff -urN linux-2.5.65-bk1/sound/core/seq/seq_ports.c linux-2.5.65-bk2/sound/core/seq/seq_ports.c
--- linux-2.5.65-bk1/sound/core/seq/seq_ports.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/sound/core/seq/seq_ports.c	Mon Mar 31 12:39:51 2003
@@ -351,6 +351,7 @@
 
 	/* information about supported channels/voices */
 	port->midi_channels = info->midi_channels;
+	port->midi_voices = info->midi_voices;
 	port->synth_voices = info->synth_voices;
 
 	return 0;
@@ -372,6 +373,7 @@
 
 	/* information about supported channels/voices */
 	info->midi_channels = port->midi_channels;
+	info->midi_voices = port->midi_voices;
 	info->synth_voices = port->synth_voices;
 
 	/* get subscriber counts */
@@ -611,7 +613,7 @@
 int snd_seq_event_port_attach(int client,
 			      snd_seq_port_callback_t *pcbp,
 			      int cap, int type, int midi_channels,
-			      char *portname)
+			      int midi_voices, char *portname)
 {
 	snd_seq_port_info_t portinfo;
 	int  ret;
@@ -628,6 +630,7 @@
 	portinfo.type = type;
 	portinfo.kernel = pcbp;
 	portinfo.midi_channels = midi_channels;
+	portinfo.midi_voices = midi_voices;
 
 	/* Create it */
 	ret = snd_seq_kernel_client_ctl(client,
diff -urN linux-2.5.65-bk1/sound/core/seq/seq_ports.h linux-2.5.65-bk2/sound/core/seq/seq_ports.h
--- linux-2.5.65-bk1/sound/core/seq/seq_ports.h	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/sound/core/seq/seq_ports.h	Mon Mar 31 12:39:51 2003
@@ -81,6 +81,7 @@
 
 	/* supported channels */
 	int midi_channels;
+	int midi_voices;
 	int synth_voices;
 		
 } client_port_t;
diff -urN linux-2.5.65-bk1/sound/core/seq/seq_timer.c linux-2.5.65-bk2/sound/core/seq/seq_timer.c
--- linux-2.5.65-bk1/sound/core/seq/seq_timer.c	Mon Mar 17 13:44:38 2003
+++ linux-2.5.65-bk2/sound/core/seq/seq_timer.c	Mon Mar 31 12:39:51 2003
@@ -262,34 +262,33 @@
 	snd_timer_instance_t *t;
 	seq_timer_t *tmr;
 	char str[32];
+	int err;
 
 	tmr = q->timer;
 	snd_assert(tmr != NULL, return -EINVAL);
 	if (tmr->timeri)
 		return -EBUSY;
 	sprintf(str, "sequencer queue %i", q->queue);
-	if (tmr->type == SNDRV_SEQ_TIMER_ALSA) {	/* standard ALSA timer */
-		if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
-			tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
-		t = snd_timer_open(str, &tmr->alsa_id, q->queue);
-		if (t == NULL && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) {
-			if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL ||
-			    tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) {
-				snd_timer_id_t tid;
-				memset(&tid, 0, sizeof(tid));
-				tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
-				tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
-				tid.card = -1;
-				tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
-				t = snd_timer_open(str, &tid, q->queue);
-			}
-			if (t == NULL) {
-				snd_printk(KERN_ERR "fatal error: cannot create timer\n");
-				return -ENODEV;
-			}
-		}
-	} else {
+	if (tmr->type != SNDRV_SEQ_TIMER_ALSA)	/* standard ALSA timer */
 		return -EINVAL;
+	if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
+		tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
+	err = snd_timer_open(&t, str, &tmr->alsa_id, q->queue);
+	if (err < 0 && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) {
+		if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL ||
+		    tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) {
+			snd_timer_id_t tid;
+			memset(&tid, 0, sizeof(tid));
+			tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
+			tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
+			tid.card = -1;
+			tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
+			err = snd_timer_open(&t, str, &tid, q->queue);
+		}
+		if (err < 0) {
+			snd_printk(KERN_ERR "seq fatal error: cannot create timer (%i)\n", err);
+			return err;
+		}
 	}
 	t->callback = snd_seq_timer_interrupt;
 	t->callback_data = q;
@@ -319,7 +318,7 @@
 	if (!tmr->running)
 		return 0;
 	tmr->running = 0;
-	snd_timer_stop(tmr->timeri);
+	snd_timer_pause(tmr->timeri);
 	return 0;
 }
 
diff -urN linux-2.5.65-bk1/sound/core/sgbuf.c linux-2.5.65-bk2/sound/core/sgbuf.c
--- linux-2.5.65-bk1/sound/core/sgbuf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/sound/core/sgbuf.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,131 @@
+/*
+ * Scatter-Gather buffer
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <sound/memalloc.h>
+
+
+/* table entries are align to 32 */
+#define SGBUF_TBL_ALIGN		32
+#define sgbuf_align_table(tbl)	((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
+
+
+/**
+ * snd_malloc_sgbuf_pages - allocate the pages for the PCI SG buffer
+ * @pci: the pci device pointer
+ * @size: the requested buffer size in bytes
+ * @dmab: the buffer record to store
+ *
+ * Initializes the SG-buffer table and allocates the buffer pages
+ * for the given size.
+ * The pages are mapped to the virtually continuous memory.
+ *
+ * This function is usually called from the middle-level functions such as
+ * snd_pcm_lib_malloc_pages().
+ *
+ * Returns the mapped virtual address of the buffer if allocation was
+ * successful, or NULL at error.
+ */
+void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer *dmab)
+{
+	struct snd_sg_buf *sgbuf;
+	unsigned int i, pages;
+
+	dmab->area = NULL;
+	dmab->addr = 0;
+	dmab->private_data = sgbuf = kmalloc(sizeof(*sgbuf), GFP_KERNEL);
+	if (! sgbuf)
+		return NULL;
+	memset(sgbuf, 0, sizeof(*sgbuf));
+	sgbuf->pci = pci;
+	pages = snd_sgbuf_aligned_pages(size);
+	sgbuf->tblsize = sgbuf_align_table(pages);
+	sgbuf->table = kmalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL);
+	if (! sgbuf->table)
+		goto _failed;
+	memset(sgbuf->table, 0, sizeof(*sgbuf->table) * sgbuf->tblsize);
+	sgbuf->page_table = kmalloc(sizeof(*sgbuf->page_table) * sgbuf->tblsize, GFP_KERNEL);
+	if (! sgbuf->page_table)
+		goto _failed;
+	memset(sgbuf->page_table, 0, sizeof(*sgbuf->page_table) * sgbuf->tblsize);
+
+	/* allocate each page */
+	for (i = 0; i < pages; i++) {
+		void *ptr;
+		dma_addr_t addr;
+		ptr = snd_malloc_pci_page(sgbuf->pci, &addr);
+		if (! ptr)
+			goto _failed;
+		sgbuf->table[i].buf = ptr;
+		sgbuf->table[i].addr = addr;
+		sgbuf->page_table[i] = virt_to_page(ptr);
+		sgbuf->pages++;
+	}
+
+	sgbuf->size = size;
+	dmab->area = vmap(sgbuf->page_table, sgbuf->pages);
+	if (! dmab->area)
+		goto _failed;
+	return dmab->area;
+
+ _failed:
+	snd_free_sgbuf_pages(dmab); /* free the table */
+	return NULL;
+}
+
+/**
+ * snd_free_sgbuf_pages - free the sg buffer
+ * @dmab: buffer record
+ *
+ * Releases the pages and the SG-buffer table.
+ *
+ * This function is called usually from the middle-level function
+ * such as snd_pcm_lib_free_pages().
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ */
+int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
+{
+	struct snd_sg_buf *sgbuf = dmab->private_data;
+	int i;
+
+	if (! sgbuf)
+		return -EINVAL;
+
+	for (i = 0; i < sgbuf->pages; i++)
+		snd_free_pci_page(sgbuf->pci, sgbuf->table[i].buf, sgbuf->table[i].addr);
+	if (dmab->area)
+		vunmap(dmab->area);
+	dmab->area = NULL;
+
+	if (sgbuf->table)
+		kfree(sgbuf->table);
+	if (sgbuf->page_table)
+		kfree(sgbuf->page_table);
+	kfree(sgbuf);
+	dmab->private_data = NULL;
+	
+	return 0;
+}
diff -urN linux-2.5.65-bk1/sound/core/sound.c linux-2.5.65-bk2/sound/core/sound.c
--- linux-2.5.65-bk1/sound/core/sound.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/sound/core/sound.c	Mon Mar 31 12:39:51 2003
@@ -432,24 +432,6 @@
 #endif
 EXPORT_SYMBOL(snd_kcalloc);
 EXPORT_SYMBOL(snd_kmalloc_strdup);
-EXPORT_SYMBOL(snd_malloc_pages);
-EXPORT_SYMBOL(snd_malloc_pages_fallback);
-EXPORT_SYMBOL(snd_free_pages);
-#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
-EXPORT_SYMBOL(snd_malloc_isa_pages);
-EXPORT_SYMBOL(snd_malloc_isa_pages_fallback);
-#endif
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(snd_malloc_pci_pages);
-EXPORT_SYMBOL(snd_malloc_pci_pages_fallback);
-EXPORT_SYMBOL(snd_malloc_pci_page);
-EXPORT_SYMBOL(snd_free_pci_pages);
-#endif
-#ifdef CONFIG_SBUS
-EXPORT_SYMBOL(snd_malloc_sbus_pages);
-EXPORT_SYMBOL(snd_malloc_sbus_pages_fallback);
-EXPORT_SYMBOL(snd_free_sbus_pages);
-#endif
 EXPORT_SYMBOL(copy_to_user_fromio);
 EXPORT_SYMBOL(copy_from_user_toio);
   /* init.c */
@@ -522,9 +504,6 @@
 #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
 EXPORT_SYMBOL(snd_verbose_printd);
 #endif
-#if defined(CONFIG_SND_DEBUG) && !defined(CONFIG_SND_VERBOSE_PRINTK)
-EXPORT_SYMBOL(snd_printd);
-#endif
   /* wrappers */
 #ifdef CONFIG_SND_DEBUG_MEMORY
 EXPORT_SYMBOL(snd_wrapper_kmalloc);
@@ -532,6 +511,3 @@
 EXPORT_SYMBOL(snd_wrapper_vmalloc);
 EXPORT_SYMBOL(snd_wrapper_vfree);
 #endif
-#ifdef HACK_PCI_ALLOC_CONSISTENT
-EXPORT_SYMBOL(snd_pci_hack_alloc_consistent);
-#endif 
diff -urN linux-2.5.65-bk1/sound/core/timer.c linux-2.5.65-bk2/sound/core/timer.c
--- linux-2.5.65-bk1/sound/core/timer.c	Mon Mar 17 13:44:14 2003
+++ linux-2.5.65-bk2/sound/core/timer.c	Mon Mar 31 12:39:51 2003
@@ -51,6 +51,7 @@
 
 typedef struct {
 	snd_timer_instance_t *timeri;
+	int tread;			/* enhanced read with timestamps and events */
 	unsigned long ticks;
 	unsigned long overrun;
 	int qhead;
@@ -58,7 +59,11 @@
 	int qused;
 	int queue_size;
 	snd_timer_read_t *queue;
+	snd_timer_tread_t *tqueue;
 	spinlock_t qlock;
+	unsigned long last_resolution;
+	unsigned int filter;
+	struct timespec tstamp;		/* trigger tstamp */
 	wait_queue_head_t qchange_sleep;
 	struct fasync_struct *fasync;
 } snd_timer_user_t;
@@ -228,8 +233,9 @@
  * open a timer instance
  * when opening a master, the slave id must be here given.
  */
-snd_timer_instance_t *snd_timer_open(char *owner, snd_timer_id_t *tid,
-				     unsigned int slave_id)
+int snd_timer_open(snd_timer_instance_t **ti,
+		   char *owner, snd_timer_id_t *tid,
+		   unsigned int slave_id)
 {
 	snd_timer_t *timer;
 	snd_timer_instance_t *timeri = NULL;
@@ -239,7 +245,7 @@
 		if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
 		    tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
 			snd_printd("invalid slave class %i\n", tid->dev_sclass);
-			return NULL;
+			return -EINVAL;
 		}
 		down(&register_mutex);
 		timeri = snd_timer_instance_new(owner, NULL);
@@ -249,7 +255,8 @@
 		list_add_tail(&timeri->open_list, &snd_timer_slave_list);
 		snd_timer_check_slave(timeri);
 		up(&register_mutex);
-		return timeri;
+		*ti = timeri;
+		return 0;
 	}
 
 	/* open a master instance */
@@ -264,6 +271,13 @@
 	}
 #endif
 	if (timer) {
+		if (!list_empty(&timer->open_list_head)) {
+			timeri = (snd_timer_instance_t *)list_entry(timer->open_list_head.next, snd_timer_instance_t, open_list);
+			if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
+				up(&register_mutex);
+				return -EBUSY;
+			}
+		}
 		timeri = snd_timer_instance_new(owner, timer);
 		if (timeri) {
 			timeri->slave_class = tid->dev_sclass;
@@ -273,12 +287,16 @@
 			list_add_tail(&timeri->open_list, &timer->open_list_head);
 			snd_timer_check_master(timeri);
 		}
+	} else {
+		up(&register_mutex);
+		return -ENODEV;
 	}
 	up(&register_mutex);
-	return timeri;
+	*ti = timeri;
+	return 0;
 }
 
-static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag);
+static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event);
 
 /*
  * close a timer instance
@@ -307,7 +325,7 @@
 		list_for_each_safe(p, n, &timeri->slave_list_head) {
 			slave = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list);
 			spin_lock_irq(&slave_active_lock);
-			_snd_timer_stop(slave, 1);
+			_snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
 			list_del(p);
 			list_add_tail(p, &snd_timer_slave_list);
 			slave->master = NULL;
@@ -340,6 +358,37 @@
 	return 0;
 }
 
+static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event event)
+{
+	snd_timer_t *timer;
+	unsigned long flags;
+	unsigned long resolution = 0;
+	snd_timer_instance_t *ts;
+	struct list_head *n;
+	struct timespec tstamp;
+
+	snd_timestamp_now(&tstamp, 1);
+	snd_assert(event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE, return);
+	if (event == SNDRV_TIMER_EVENT_START || event == SNDRV_TIMER_EVENT_CONTINUE)
+		resolution = snd_timer_resolution(ti);
+	if (ti->ccallback)
+		ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution);
+	if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
+		return;
+	timer = ti->timer;
+	if (timer == NULL)
+		return;
+	if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
+		return;
+	spin_lock_irqsave(&timer->lock, flags);
+	list_for_each(n, &ti->slave_active_head) {
+		ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list);
+		if (ts->ccallback)
+			ts->ccallback(ti, event + 100, &tstamp, resolution);
+	}
+	spin_unlock_irqrestore(&timer->lock, flags);
+}
+
 static int snd_timer_start1(snd_timer_t *timer, snd_timer_instance_t *timeri, unsigned long sticks)
 {
 	list_del(&timeri->active_list);
@@ -380,8 +429,11 @@
 
 	if (timeri == NULL || ticks < 1)
 		return -EINVAL;
-	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
-		return snd_timer_start_slave(timeri);
+	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
+		result = snd_timer_start_slave(timeri);
+		snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
+		return result;
+	}
 	timer = timeri->timer;
 	if (timer == NULL)
 		return -EINVAL;
@@ -390,17 +442,17 @@
 	timeri->pticks = 0;
 	result = snd_timer_start1(timer, timeri, ticks);
 	spin_unlock_irqrestore(&timer->lock, flags);
+	snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
 	return result;
 }
 
-static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag)
+static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event)
 {
 	snd_timer_t *timer;
 	unsigned long flags;
 
 	snd_assert(timeri != NULL, return -ENXIO);
 
-
 	timer = timeri->timer;
 	if (! timer)
 		return -EINVAL;
@@ -429,6 +481,8 @@
 	if (!keep_flag)
 		timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING|SNDRV_TIMER_IFLG_START);
 	spin_unlock_irqrestore(&timer->lock, flags);
+	if (event != SNDRV_TIMER_EVENT_RESOLUTION)
+		snd_timer_notify1(timeri, event);
 	return 0;
 }
 
@@ -439,7 +493,19 @@
  */
 int snd_timer_stop(snd_timer_instance_t * timeri)
 {
-	return _snd_timer_stop(timeri, 0);
+	snd_timer_t *timer;
+	unsigned long flags;
+	int err;
+
+	err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP);
+	if (err < 0)
+		return err;
+	timer = timeri->timer;
+	spin_lock_irqsave(&timer->lock, flags);
+	timeri->cticks = timeri->ticks;
+	timeri->pticks = 0;
+	spin_unlock_irqrestore(&timer->lock, flags);
+	return 0;
 }
 
 /*
@@ -464,10 +530,19 @@
 	timeri->pticks = 0;
 	result = snd_timer_start1(timer, timeri, timer->sticks);
 	spin_unlock_irqrestore(&timer->lock, flags);
+	snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE);
 	return result;
 }
 
 /*
+ * pause.. remember the ticks left
+ */
+int snd_timer_pause(snd_timer_instance_t * timeri)
+{
+	return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE);
+}
+
+/*
  * reschedule the timer
  *
  * start pending instances and check the scheduling ticks.
@@ -774,6 +849,35 @@
 	return snd_timer_unregister(timer);
 }
 
+void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct timespec *tstamp)
+{
+	unsigned long flags;
+	unsigned long resolution = 0;
+	snd_timer_instance_t *ti, *ts;
+	struct list_head *p, *n;
+
+	snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return);	
+	snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return);
+	spin_lock_irqsave(&timer->lock, flags);
+	if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE) {
+		if (timer->hw.c_resolution)
+			resolution = timer->hw.c_resolution(timer);
+		else
+			resolution = timer->hw.resolution;
+	}
+	list_for_each(p, &timer->active_list_head) {
+		ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list);
+		if (ti->ccallback)
+			ti->ccallback(ti, event, tstamp, resolution);
+		list_for_each(n, &ti->slave_active_head) {
+			ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list);
+			if (ts->ccallback)
+				ts->ccallback(ts, event, tstamp, resolution);
+		}
+	}
+	spin_unlock_irqrestore(&timer->lock, flags);
+}
+
 /*
  * exported functions for global timers
  */
@@ -938,9 +1042,17 @@
 {
 	snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
 	snd_timer_read_t *r;
-	int _wake = 0;
+	int prev;
 	
 	spin_lock(&tu->qlock);
+	if (tu->qused > 0) {
+		prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
+		r = &tu->queue[prev];
+		if (r->resolution == resolution) {
+			r->ticks += ticks;
+			goto __wake;
+		}
+	}
 	if (tu->qused >= tu->queue_size) {
 		tu->overrun++;
 	} else {
@@ -949,15 +1061,95 @@
 		r->resolution = resolution;
 		r->ticks = ticks;
 		tu->qused++;
-		_wake++;
 	}
+      __wake:
 	spin_unlock(&tu->qlock);
-	if (_wake) {
-		kill_fasync(&tu->fasync, SIGIO, POLL_IN);
-		wake_up(&tu->qchange_sleep);
+	kill_fasync(&tu->fasync, SIGIO, POLL_IN);
+	wake_up(&tu->qchange_sleep);
+}
+
+static void snd_timer_user_append_to_tqueue(snd_timer_user_t *tu, snd_timer_tread_t *tread)
+{
+	if (tu->qused >= tu->queue_size) {
+		tu->overrun++;
+	} else {
+		memcpy(&tu->queue[tu->qtail++], tread, sizeof(*tread));
+		tu->qused++;
 	}
 }
 
+static void snd_timer_user_ccallback(snd_timer_instance_t *timeri,
+				     enum sndrv_timer_event event,
+				     struct timespec *tstamp,
+				     unsigned long resolution)
+{
+	snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
+	snd_timer_tread_t r1;
+
+	if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE)
+		tu->tstamp = *tstamp;
+	if ((tu->filter & (1 << event)) == 0 || !tu->tread)
+		return;
+	r1.event = event;
+	r1.tstamp = *tstamp;
+	r1.val = resolution;
+	spin_lock(&tu->qlock);
+	snd_timer_user_append_to_tqueue(tu, &r1);
+	spin_unlock(&tu->qlock);
+}
+
+static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri,
+				      unsigned long resolution,
+				      unsigned long ticks)
+{
+	snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
+	snd_timer_tread_t *r, r1;
+	struct timespec tstamp;
+	int prev, append = 0;
+
+	snd_timestamp_zero(&tstamp);
+	spin_lock(&tu->qlock);
+	if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION)|(1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
+		spin_unlock(&tu->qlock);
+		return;
+	}
+	if (tu->last_resolution != resolution || ticks > 0)
+		snd_timestamp_now(&tstamp, 1);
+	if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) {
+		r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
+		r1.tstamp = tstamp;
+		r1.val = resolution;
+		snd_timer_user_append_to_tqueue(tu, &r1);
+		tu->last_resolution = resolution;
+		append++;
+	}
+	if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
+		goto __wake;
+	if (ticks == 0)
+		goto __wake;
+	if (tu->qused > 0) {
+		prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
+		r = &tu->tqueue[prev];
+		if (r->event == SNDRV_TIMER_EVENT_TICK) {
+			r->tstamp = tstamp;
+			r->val += ticks;
+			append++;
+			goto __wake;
+		}
+	}
+	r1.event = SNDRV_TIMER_EVENT_TICK;
+	r1.tstamp = tstamp;
+	r1.val = ticks;
+	snd_timer_user_append_to_tqueue(tu, &r1);
+	append++;
+      __wake:
+	spin_unlock(&tu->qlock);
+	if (append == 0)
+		return;
+	kill_fasync(&tu->fasync, SIGIO, POLL_IN);
+	wake_up(&tu->qchange_sleep);
+}
+
 static int snd_timer_user_open(struct inode *inode, struct file *file)
 {
 	snd_timer_user_t *tu;
@@ -990,6 +1182,8 @@
 			snd_timer_close(tu->timeri);
 		if (tu->queue)
 			kfree(tu->queue);
+		if (tu->tqueue)
+			kfree(tu->tqueue);
 		snd_magic_kfree(tu);
 	}
 	return 0;
@@ -1104,11 +1298,110 @@
 	return 0;
 } 
 
+static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t *_ginfo)
+{
+	snd_timer_ginfo_t ginfo;
+	snd_timer_id_t tid;
+	snd_timer_t *t;
+	struct list_head *p;
+	int err = 0;
+
+	if (copy_from_user(&ginfo, _ginfo, sizeof(ginfo)))
+		return -EFAULT;
+	tid = ginfo.tid;
+	memset(&ginfo, 0, sizeof(ginfo));
+	ginfo.tid = tid;
+	down(&register_mutex);
+	t = snd_timer_find(&tid);
+	if (t != NULL) {
+		ginfo.card = t->card ? t->card->number : -1;
+		if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
+			ginfo.flags |= SNDRV_TIMER_FLG_SLAVE;
+		strncpy(ginfo.id, t->id, sizeof(ginfo.id)-1);
+		strncpy(ginfo.name, t->name, sizeof(ginfo.name)-1);
+		ginfo.resolution = t->hw.resolution;
+		if (t->hw.resolution_min > 0) {
+			ginfo.resolution_min = t->hw.resolution_min;
+			ginfo.resolution_max = t->hw.resolution_max;
+		}
+		list_for_each(p, &t->open_list_head) {
+			ginfo.clients++;
+		}
+	} else {
+		err = -ENODEV;
+	}
+	up(&register_mutex);
+	if (err >= 0 && copy_to_user(_ginfo, &ginfo, sizeof(ginfo)))
+		err = -EFAULT;
+	return err;
+}
+
+static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t *_gparams)
+{
+	snd_timer_gparams_t gparams;
+	snd_timer_t *t;
+	int err;
+
+	if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
+		return -EFAULT;
+	down(&register_mutex);
+	t = snd_timer_find(&gparams.tid);
+	if (t != NULL) {
+		if (list_empty(&t->open_list_head)) {
+			if (t->hw.set_period)
+				err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
+			else
+				err = -ENOSYS;
+		} else {
+			err = -EBUSY;
+		}
+	} else {
+		err = -ENODEV;
+	}
+	up(&register_mutex);
+	return err;
+}
+
+static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t *_gstatus)
+{
+	snd_timer_gstatus_t gstatus;
+	snd_timer_id_t tid;
+	snd_timer_t *t;
+	int err = 0;
+
+	if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus)))
+		return -EFAULT;
+	tid = gstatus.tid;
+	memset(&gstatus, 0, sizeof(gstatus));
+	gstatus.tid = tid;
+	down(&register_mutex);
+	t = snd_timer_find(&tid);
+	if (t != NULL) {
+		if (t->hw.c_resolution)
+			gstatus.resolution = t->hw.c_resolution(t);
+		else
+			gstatus.resolution = t->hw.resolution;
+		if (t->hw.precise_resolution) {
+			t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den);
+		} else {
+			gstatus.resolution_num = 1;
+			gstatus.resolution_den = gstatus.resolution;
+		}
+	} else {
+		err = -ENODEV;
+	}
+	up(&register_mutex);
+	if (err >= 0 && copy_from_user(_gstatus, &gstatus, sizeof(gstatus)))
+		err = -EFAULT;
+	return err;
+}
+
 static int snd_timer_user_tselect(struct file *file, snd_timer_select_t *_tselect)
 {
 	snd_timer_user_t *tu;
 	snd_timer_select_t tselect;
 	char str[32];
+	int err;
 	
 	tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
 	if (tu->timeri)
@@ -1118,10 +1411,34 @@
 	sprintf(str, "application %i", current->pid);
 	if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
 		tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
-	if ((tu->timeri = snd_timer_open(str, &tselect.id, current->pid)) == NULL)
-		return -ENODEV;
+	if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0)
+		return err;
+
+	if (tu->queue) {
+		kfree(tu->queue);
+		tu->queue = NULL;
+	}
+	if (tu->tqueue) {
+		kfree(tu->tqueue);
+		tu->tqueue = NULL;
+	}
+	if (tu->tread) {
+		tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
+		if (tu->tqueue == NULL) {
+			snd_timer_close(tu->timeri);
+			return -ENOMEM;
+		}
+	} else {
+		tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
+		if (tu->queue == NULL) {
+			snd_timer_close(tu->timeri);
+			return -ENOMEM;
+		}
+	}
+	
 	tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
-	tu->timeri->callback = snd_timer_user_interrupt;
+	tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
+	tu->timeri->ccallback = snd_timer_user_ccallback;
 	tu->timeri->callback_data = (void *)tu;
 	return 0;
 }
@@ -1142,7 +1459,6 @@
 		info.flags |= SNDRV_TIMER_FLG_SLAVE;
 	strncpy(info.id, t->id, sizeof(info.id)-1);
 	strncpy(info.name, t->name, sizeof(info.name)-1);
-	info.ticks = t->hw.ticks;
 	info.resolution = t->hw.resolution;
 	if (copy_to_user(_info, &info, sizeof(*_info)))
 		return -EFAULT;
@@ -1156,6 +1472,7 @@
 	snd_timer_params_t params;
 	snd_timer_t *t;
 	snd_timer_read_t *tr;
+	snd_timer_tread_t *ttr;
 	int err;
 	
 	tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
@@ -1172,6 +1489,19 @@
 		err = -EINVAL;
 		goto _end;
 	}
+	if (params.filter & ~((1<<SNDRV_TIMER_EVENT_RESOLUTION)|
+			      (1<<SNDRV_TIMER_EVENT_TICK)|
+			      (1<<SNDRV_TIMER_EVENT_START)|
+			      (1<<SNDRV_TIMER_EVENT_STOP)|
+			      (1<<SNDRV_TIMER_EVENT_CONTINUE)|
+			      (1<<SNDRV_TIMER_EVENT_PAUSE)|
+			      (1<<SNDRV_TIMER_EVENT_MSTART)|
+			      (1<<SNDRV_TIMER_EVENT_MSTOP)|
+			      (1<<SNDRV_TIMER_EVENT_MCONTINUE)|
+			      (1<<SNDRV_TIMER_EVENT_MPAUSE))) {
+		err = -EINVAL;
+		goto _end;
+	}
 	snd_timer_stop(tu->timeri);
 	spin_lock_irqsave(&t->lock, flags);
 	if (params.flags & SNDRV_TIMER_PSFLG_AUTO) {
@@ -1179,20 +1509,31 @@
 	} else {
 		tu->timeri->flags &= ~SNDRV_TIMER_IFLG_AUTO;
 	}
+	if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE) {
+		tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
+	} else {
+		tu->timeri->flags &= ~SNDRV_TIMER_IFLG_EXCLUSIVE;
+	}
 	spin_unlock_irqrestore(&t->lock, flags);
 	if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) {
-		tr = (snd_timer_read_t *)kmalloc(params.queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
-		if (tr) {
-			kfree(tu->queue);
-			tu->queue_size = params.queue_size;
-			tu->queue = tr;
+		if (tu->tread) {
+			ttr = (snd_timer_tread_t *)kmalloc(params.queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
+			if (ttr) {
+				kfree(tu->tqueue);
+				tu->queue_size = params.queue_size;
+				tu->tqueue = ttr;
+			}
+		} else {
+			tr = (snd_timer_read_t *)kmalloc(params.queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
+			if (tr) {
+				kfree(tu->queue);
+				tu->queue_size = params.queue_size;
+				tu->queue = tr;
+			}
 		}
 	}
-	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) {
-		tu->ticks = 1;
-	} else {
-		tu->ticks = params.ticks;
-	}
+	tu->filter = params.filter;
+	tu->ticks = params.ticks;
 	err = 0;
  _end:
 	if (copy_to_user(_params, &params, sizeof(params)))
@@ -1209,6 +1550,7 @@
 	tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
 	snd_assert(tu->timeri != NULL, return -ENXIO);
 	memset(&status, 0, sizeof(status));
+	status.tstamp = tu->tstamp;
 	status.resolution = snd_timer_resolution(tu->timeri);
 	status.lost = tu->timeri->lost;
 	status.overrun = tu->overrun;
@@ -1229,6 +1571,7 @@
 	snd_assert(tu->timeri != NULL, return -ENXIO);
 	snd_timer_stop(tu->timeri);
 	tu->timeri->lost = 0;
+	tu->last_resolution = 0;
 	return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0;
 }
 
@@ -1264,6 +1607,23 @@
 		return put_user(SNDRV_TIMER_VERSION, (int *)arg) ? -EFAULT : 0;
 	case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
 		return snd_timer_user_next_device((snd_timer_id_t *)arg);
+	case SNDRV_TIMER_IOCTL_TREAD:
+	{
+		int xarg;
+		
+		if (tu->timeri)		/* too late */
+			return -EBUSY;
+		if (get_user(xarg, (int *) arg))
+			return -EFAULT;
+		tu->tread = xarg ? 1 : 0;
+		return 0;
+	}
+	case SNDRV_TIMER_IOCTL_GINFO:
+		return snd_timer_user_ginfo(file, (snd_timer_ginfo_t *)arg);
+	case SNDRV_TIMER_IOCTL_GPARAMS:
+		return snd_timer_user_gparams(file, (snd_timer_gparams_t *)arg);
+	case SNDRV_TIMER_IOCTL_GSTATUS:
+		return snd_timer_user_gstatus(file, (snd_timer_gstatus_t *)arg);
 	case SNDRV_TIMER_IOCTL_SELECT:
 		return snd_timer_user_tselect(file, (snd_timer_select_t *)arg);
 	case SNDRV_TIMER_IOCTL_INFO:
@@ -1297,12 +1657,13 @@
 static ssize_t snd_timer_user_read(struct file *file, char *buffer, size_t count, loff_t *offset)
 {
 	snd_timer_user_t *tu;
-	long result = 0;
+	long result = 0, unit;
 	int err = 0;
 	
 	tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+	unit = tu->tread ? sizeof(snd_timer_tread_t) : sizeof(snd_timer_read_t);
 	spin_lock_irq(&tu->qlock);
-	while (count - result >= sizeof(snd_timer_read_t)) {
+	while ((long)count - result >= unit) {
 		while (!tu->qused) {
 			wait_queue_t wait;
 
@@ -1331,15 +1692,22 @@
 		if (err < 0)
 			break;
 
-		if (copy_to_user(buffer, &tu->queue[tu->qhead++], sizeof(snd_timer_read_t))) {
-			err = -EFAULT;
-			break;
+		if (tu->tread) {
+			if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], sizeof(snd_timer_tread_t))) {
+				err = -EFAULT;
+				break;
+			}
+		} else {
+			if (copy_to_user(buffer, &tu->queue[tu->qhead++], sizeof(snd_timer_read_t))) {
+				err = -EFAULT;
+				break;
+			}
 		}
 
 		tu->qhead %= tu->queue_size;
 
-		result += sizeof(snd_timer_read_t);
-		buffer += sizeof(snd_timer_read_t);
+		result += unit;
+		buffer += unit;
 
 		spin_lock_irq(&tu->qlock);
 		tu->qused--;
@@ -1442,7 +1810,9 @@
 EXPORT_SYMBOL(snd_timer_start);
 EXPORT_SYMBOL(snd_timer_stop);
 EXPORT_SYMBOL(snd_timer_continue);
+EXPORT_SYMBOL(snd_timer_pause);
 EXPORT_SYMBOL(snd_timer_new);
+EXPORT_SYMBOL(snd_timer_notify);
 EXPORT_SYMBOL(snd_timer_global_new);
 EXPORT_SYMBOL(snd_timer_global_free);
 EXPORT_SYMBOL(snd_timer_global_register);
diff -urN linux-2.5.65-bk1/sound/core/wrappers.c linux-2.5.65-bk2/sound/core/wrappers.c
--- linux-2.5.65-bk1/sound/core/wrappers.c	Mon Mar 17 13:43:44 2003
+++ linux-2.5.65-bk2/sound/core/wrappers.c	Mon Mar 31 12:39:51 2003
@@ -49,59 +49,3 @@
 }
 #endif
 
-
-/* check the condition in <sound/core.h> !! */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
-#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
-
-#include <linux/pci.h>
-
-/* to be sure... */
-#ifdef HACK_PCI_ALLOC_CONSISTENT
-#error pci_alloc_consistent hack is already defined!!
-#endif
-
-/*
- * A dirty hack... when the kernel code is fixed this should be removed.
- *
- * since pci_alloc_consistent always tries GFP_DMA when the requested
- * pci memory region is below 32bit, it happens quite often that even
- * 2 order of pages cannot be allocated.
- *
- * so in the following, we allocate at first without dma_mask, so that
- * allocation will be done without GFP_DMA.  if the area doesn't match
- * with the requested region, then realloate with the original dma_mask
- * again.
- */
-
-void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
-				    dma_addr_t *dma_handle)
-{
-	void *ret;
-	u64 dma_mask;
-	unsigned long rmask;
-
-	if (hwdev == NULL)
-		return pci_alloc_consistent(hwdev, size, dma_handle);
-	dma_mask = hwdev->dma_mask;
-	rmask = ~((unsigned long)dma_mask);
-	hwdev->dma_mask = 0xffffffff; /* do without masking */
-	ret = pci_alloc_consistent(hwdev, size, dma_handle);
-	hwdev->dma_mask = dma_mask; /* restore */
-	if (ret) {
-		/* obtained address is out of range? */
-		if (((unsigned long)*dma_handle + size - 1) & rmask) {
-			/* reallocate with the proper mask */
-			pci_free_consistent(hwdev, size, ret, *dma_handle);
-			ret = pci_alloc_consistent(hwdev, size, dma_handle);
-		}
-	} else {
-		/* wish to success now with the proper mask... */
-		if (dma_mask != 0xffffffff)
-			ret = pci_alloc_consistent(hwdev, size, dma_handle);
-	}
-	return ret;
-}
-
-#endif
-#endif
diff -urN linux-2.5.65-bk1/sound/drivers/dummy.c linux-2.5.65-bk2/sound/drivers/dummy.c
--- linux-2.5.65-bk1/sound/drivers/dummy.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/sound/drivers/dummy.c	Mon Mar 31 12:39:51 2003
@@ -54,6 +54,15 @@
 #define USE_PERIODS_MAX		2
 #endif
 
+#if 0 /* ICE1712 emulation */
+#define MAX_BUFFER_SIZE		(256 * 1024)
+#define USE_FORMATS		SNDRV_PCM_FMTBIT_S32_LE
+#define USE_CHANNELS_MIN	12
+#define USE_CHANNELS_MAX	12
+#define USE_PERIODS_MIN		1
+#define USE_PERIODS_MAX		1024
+#endif
+
 #if 0 /* UDA1341 emulation */
 #define MAX_BUFFER_SIZE		(16380)
 #define USE_FORMATS		SNDRV_PCM_FMTBIT_S16_LE
diff -urN linux-2.5.65-bk1/sound/drivers/mpu401/mpu401_uart.c linux-2.5.65-bk2/sound/drivers/mpu401/mpu401_uart.c
--- linux-2.5.65-bk1/sound/drivers/mpu401/mpu401_uart.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/sound/drivers/mpu401/mpu401_uart.c	Mon Mar 31 12:39:51 2003
@@ -21,6 +21,11 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
+ *   13-03-2003:
+ *      Added support for different kind of hardware I/O. Build in choices
+ *      are port and mmio. For other kind of I/O, set mpu->read and
+ *      mpu->write to your own I/O functions.
+ *
  */
 
 #include <sound/driver.h>
@@ -45,21 +50,43 @@
 
  */
 
-#define snd_mpu401_input_avail(mpu)	(!(inb(MPU401C(mpu)) & 0x80))
-#define snd_mpu401_output_ready(mpu)	(!(inb(MPU401C(mpu)) & 0x40))
+#define snd_mpu401_input_avail(mpu)	(!(mpu->read(mpu, MPU401C(mpu)) & 0x80))
+#define snd_mpu401_output_ready(mpu)	(!(mpu->read(mpu, MPU401C(mpu)) & 0x40))
 
 #define MPU401_RESET		0xff
 #define MPU401_ENTER_UART	0x3f
 #define MPU401_ACK		0xfe
 
+/* Build in lowlevel io */
+static void mpu401_write_port(mpu401_t *mpu, unsigned char data, unsigned long addr)
+{
+	outb(data, addr);
+}
+
+static unsigned char mpu401_read_port(mpu401_t *mpu, unsigned long addr)
+{
+	return inb(addr);
+}
+
+static void mpu401_write_mmio(mpu401_t *mpu, unsigned char data, unsigned long addr)
+{
+	writeb(data, (unsigned long*)addr);
+}
+
+static unsigned char mpu401_read_mmio(mpu401_t *mpu, unsigned long addr)
+{
+	return readb((unsigned long*)addr);
+}
+/*  */
+
 static void snd_mpu401_uart_clear_rx(mpu401_t *mpu)
 {
 	int timeout = 100000;
 	for (; timeout > 0 && snd_mpu401_input_avail(mpu); timeout--)
-		inb(MPU401D(mpu));
+		mpu->read(mpu, MPU401D(mpu));
 #ifdef CONFIG_SND_DEBUG
 	if (timeout <= 0)
-		snd_printk("cmd: clear rx timeout (status = 0x%x)\n", inb(MPU401C(mpu)));
+		snd_printk("cmd: clear rx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu)));
 #endif
 }
 
@@ -163,7 +190,7 @@
 
 	spin_lock_irqsave(&mpu->input_lock, flags);
 	if (mpu->hardware != MPU401_HW_TRID4DWAVE) {
-		outb(0x00, MPU401D(mpu));
+		mpu->write(mpu, 0x00, MPU401D(mpu));
 		/*snd_mpu401_uart_clear_rx(mpu);*/
 	}
 	/* ok. standard MPU-401 initialization */
@@ -172,28 +199,28 @@
 			udelay(10);
 #ifdef CONFIG_SND_DEBUG
 		if (!timeout)
-			snd_printk("cmd: tx timeout (status = 0x%x)\n", inb(MPU401C(mpu)));
+			snd_printk("cmd: tx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu)));
 #endif
 	}
-	outb(cmd, MPU401C(mpu));
+	mpu->write(mpu, cmd, MPU401C(mpu));
 	if (ack) {
 		ok = 0;
 		timeout = 10000;
 		while (!ok && timeout-- > 0) {
 			if (snd_mpu401_input_avail(mpu)) {
-				if (inb(MPU401D(mpu)) == MPU401_ACK)
+				if (mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
 					ok = 1;
 			}
 		}
-		if (!ok && inb(MPU401D(mpu)) == MPU401_ACK)
+		if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
 			ok = 1;
 	} else {
 		ok = 1;
 	}
 	spin_unlock_irqrestore(&mpu->input_lock, flags);
 	if (! ok)
-		snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, inb(MPU401C(mpu)), inb(MPU401D(mpu)));
-	// snd_printk("cmd: 0x%x at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, inb(MPU401C(mpu)), inb(MPU401D(mpu)));
+		snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu)));
+	// snd_printk("cmd: 0x%x at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu)));
 }
 
 /*
@@ -275,7 +302,7 @@
 		if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) {
 			/* first time - flush FIFO */
 			while (max-- > 0)
-				inb(MPU401D(mpu));
+				mpu->read(mpu, MPU401D(mpu));
 			if (mpu->irq < 0)
 				snd_mpu401_uart_add_timer(mpu, 1);
 		}
@@ -306,7 +333,7 @@
 
 	while (max-- > 0) {
 		if (snd_mpu401_input_avail(mpu)) {
-			byte = inb(MPU401D(mpu));
+			byte = mpu->read(mpu, MPU401D(mpu));
 			if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
 				snd_rawmidi_receive(mpu->substream_input, &byte, 1);
 		} else {
@@ -336,7 +363,7 @@
 		if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) {
 			for (timeout = 100; timeout > 0; timeout--) {
 				if (snd_mpu401_output_ready(mpu)) {
-					outb(byte, MPU401D(mpu));
+					mpu->write(mpu, byte, MPU401D(mpu));
 					snd_rawmidi_transmit_ack(mpu->substream_output, 1);
 					break;
 				}
@@ -460,6 +487,16 @@
 			return -EBUSY;
 		}
 	}
+	switch (hardware) {
+	case MPU401_HW_AUREAL:
+		mpu->write = mpu401_write_mmio;
+		mpu->read = mpu401_read_mmio;
+		break;
+	default:
+		mpu->write = mpu401_write_port;
+		mpu->read = mpu401_read_port;
+		break;
+	}
 	mpu->port = port;
 	if (hardware == MPU401_HW_PC98II)
 		mpu->cport = port + 2;
@@ -474,7 +511,10 @@
 	}
 	mpu->irq = irq;
 	mpu->irq_flags = irq_flags;
-	strcpy(rmidi->name, "MPU-401 (UART)");
+	if (card->shortname[0])
+		snprintf(rmidi->name, sizeof(rmidi->name), "%s MPU-401", card->shortname);
+	else
+		sprintf(rmidi->name, "MPU-401 (UART) %d-%d", card->number, device);
 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mpu401_uart_output);
 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input);
 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
diff -urN linux-2.5.65-bk1/sound/drivers/mtpav.c linux-2.5.65-bk2/sound/drivers/mtpav.c
--- linux-2.5.65-bk1/sound/drivers/mtpav.c	Mon Mar 17 13:44:39 2003
+++ linux-2.5.65-bk2/sound/drivers/mtpav.c	Mon Mar 31 12:39:51 2003
@@ -802,7 +802,7 @@
 
 #ifndef MODULE
 
-/* format is: snd-mtpav=snd_enable,index,id,
+/* format is: snd-mtpav=enable,index,id,
 			port,irq,hwports */
 
 static int __init alsa_card_mtpav_setup(char *str)
diff -urN linux-2.5.65-bk1/sound/drivers/opl3/opl3_oss.c linux-2.5.65-bk2/sound/drivers/opl3/opl3_oss.c
--- linux-2.5.65-bk1/sound/drivers/opl3/opl3_oss.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/sound/drivers/opl3/opl3_oss.c	Mon Mar 31 12:39:51 2003
@@ -101,7 +101,7 @@
 							  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
 							  SNDRV_SEQ_PORT_TYPE_MIDI_GM |
 							  SNDRV_SEQ_PORT_TYPE_SYNTH,
-							  voices,
+							  voices, voices,
 							  name);
 	if (opl3->oss_chset->port < 0) {
 		snd_midi_channel_free_set(opl3->oss_chset);
diff -urN linux-2.5.65-bk1/sound/drivers/opl3/opl3_seq.c linux-2.5.65-bk2/sound/drivers/opl3/opl3_seq.c
--- linux-2.5.65-bk1/sound/drivers/opl3/opl3_seq.c	Mon Mar 17 13:44:14 2003
+++ linux-2.5.65-bk2/sound/drivers/opl3/opl3_seq.c	Mon Mar 31 12:39:51 2003
@@ -179,8 +179,10 @@
 {
 	snd_seq_port_callback_t callbacks;
 	char name[32];
-	int opl_ver;
+	int voices, opl_ver;
 
+	voices = (opl3->hardware < OPL3_HW_OPL3) ?
+		MAX_OPL2_VOICES : MAX_OPL3_VOICES;
 	opl3->chset = snd_midi_channel_alloc_set(16);
 	if (opl3->chset == NULL)
 		return -ENOMEM;
@@ -204,7 +206,7 @@
 						      SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
 						      SNDRV_SEQ_PORT_TYPE_MIDI_GM |
 						      SNDRV_SEQ_PORT_TYPE_SYNTH,
-						      16,
+						      16, voices,
 						      name);
 	if (opl3->chset->port < 0) {
 		snd_midi_channel_free_set(opl3->chset);
diff -urN linux-2.5.65-bk1/sound/isa/ad1816a/ad1816a.c linux-2.5.65-bk2/sound/isa/ad1816a/ad1816a.c
--- linux-2.5.65-bk1/sound/isa/ad1816a/ad1816a.c	Mon Mar 17 13:43:48 2003
+++ linux-2.5.65-bk2/sound/isa/ad1816a/ad1816a.c	Mon Mar 31 12:39:51 2003
@@ -109,8 +109,8 @@
 #define ISAPNP_AD1816A(_va, _vb, _vc, _device, _fa, _fb, _fc, _audio, _mpu401) \
 	{ \
 		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		devs : { ISAPNP_DEVICE_ID(_fa, _fb, _fc, _audio), \
-			 ISAPNP_DEVICE_ID(_fa, _fb, _fc, _mpu401), } \
+		.devs = { ISAPNP_DEVICE_ID(_fa, _fb, _fc, _audio), \
+			  ISAPNP_DEVICE_ID(_fa, _fb, _fc, _mpu401), } \
 	}
 
 static struct isapnp_card_id snd_ad1816a_pnpids[] __devinitdata = {
diff -urN linux-2.5.65-bk1/sound/isa/azt2320.c linux-2.5.65-bk2/sound/isa/azt2320.c
--- linux-2.5.65-bk1/sound/isa/azt2320.c	Mon Mar 17 13:44:45 2003
+++ linux-2.5.65-bk2/sound/isa/azt2320.c	Mon Mar 31 12:39:51 2003
@@ -125,8 +125,8 @@
 #define ISAPNP_AZT2320(_va, _vb, _vc, _device, _audio, _mpu401) \
 	{ \
 		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		devs : { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
-			 ISAPNP_DEVICE_ID(_va, _vb, _vc, _mpu401), } \
+		.devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
+			  ISAPNP_DEVICE_ID(_va, _vb, _vc, _mpu401), } \
 	}
 
 static struct isapnp_card_id snd_azt2320_pnpids[] __devinitdata = {
diff -urN linux-2.5.65-bk1/sound/isa/cmi8330.c linux-2.5.65-bk2/sound/isa/cmi8330.c
--- linux-2.5.65-bk1/sound/isa/cmi8330.c	Mon Mar 17 13:43:42 2003
+++ linux-2.5.65-bk2/sound/isa/cmi8330.c	Mon Mar 31 12:39:51 2003
@@ -30,7 +30,7 @@
  *
  *  To quickly load the module,
  *
- *  modprobe -a snd-card-cmi8330 sbport=0x220 sbirq=5 sbdma8=1
+ *  modprobe -a snd-cmi8330 sbport=0x220 sbirq=5 sbdma8=1
  *    sbdma16=5 wssport=0x530 wssirq=11 wssdma=0
  *
  *  This card has two mixers and two PCM devices.  I've cheesed it such
@@ -182,8 +182,8 @@
 #define ISAPNP_CMI8330(_va, _vb, _vc, _device, _audio1, _audio2) \
 	{ \
 		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		devs : { ISAPNP_DEVICE_ID('@', '@', '@', _audio1), \
-			 ISAPNP_DEVICE_ID('@', 'X', '@', _audio2), } \
+		.devs = { ISAPNP_DEVICE_ID('@', '@', '@', _audio1), \
+			  ISAPNP_DEVICE_ID('@', 'X', '@', _audio2), } \
 	}
 
 static struct isapnp_card_id snd_cmi8330_pnpids[] __devinitdata =
diff -urN linux-2.5.65-bk1/sound/isa/dt019x.c linux-2.5.65-bk2/sound/isa/dt019x.c
--- linux-2.5.65-bk1/sound/isa/dt019x.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/sound/isa/dt019x.c	Mon Mar 31 12:39:51 2003
@@ -111,7 +111,7 @@
 	/* DT0196 / ALS-007 */
 	{
 		ISAPNP_CARD_ID('A','L','S',0x0007),
-		devs: { ISAPNP_DEVICE_ID('@','@','@',0x0001),
+		.devs = { ISAPNP_DEVICE_ID('@','@','@',0x0001),
 			ISAPNP_DEVICE_ID('@','X','@',0x0001),
 			ISAPNP_DEVICE_ID('@','H','@',0x0001) }
 	},
@@ -379,7 +379,7 @@
 
 #ifndef MODULE
 
-/* format is: snd-dt019x=enable,index,id,snd_isapnp,
+/* format is: snd-dt019x=enable,index,id,
 			  port,mpu_port,fm_port,
 			  irq,mpu_irq,dma8,dma8_size */
 
diff -urN linux-2.5.65-bk1/sound/isa/es18xx.c linux-2.5.65-bk2/sound/isa/es18xx.c
--- linux-2.5.65-bk1/sound/isa/es18xx.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/sound/isa/es18xx.c	Mon Mar 31 12:39:51 2003
@@ -1950,8 +1950,8 @@
 #define ISAPNP_ES18XX(_va, _vb, _vc, _device, _audio, _control) \
         { \
                 ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-                devs : { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
-                         ISAPNP_DEVICE_ID(_va, _vb, _vc, _control) } \
+                .devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
+                          ISAPNP_DEVICE_ID(_va, _vb, _vc, _control) } \
         }
 
 static struct isapnp_card_id snd_audiodrive_pnpids[] __devinitdata = {
diff -urN linux-2.5.65-bk1/sound/isa/gus/gus_pcm.c linux-2.5.65-bk2/sound/isa/gus/gus_pcm.c
--- linux-2.5.65-bk1/sound/isa/gus/gus_pcm.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/sound/isa/gus/gus_pcm.c	Mon Mar 31 12:39:51 2003
@@ -620,7 +620,7 @@
 static snd_pcm_hardware_t snd_gf1_pcm_playback =
 {
 	.info =			SNDRV_PCM_INFO_NONINTERLEAVED,
-	formats:		(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
+	.formats		= (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
 				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
 	.rate_min =		5510,
diff -urN linux-2.5.65-bk1/sound/isa/gus/gus_synth.c linux-2.5.65-bk2/sound/isa/gus/gus_synth.c
--- linux-2.5.65-bk1/sound/isa/gus/gus_synth.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/sound/isa/gus/gus_synth.c	Mon Mar 31 12:39:51 2003
@@ -197,7 +197,7 @@
 						   SNDRV_SEQ_PORT_TYPE_MIDI_GS |
 						   SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
 						   SNDRV_SEQ_PORT_TYPE_SYNTH,
-						   16,
+						   16, 0,
 						   name);
 	if (p->chset->port < 0) {
 		result = p->chset->port;
diff -urN linux-2.5.65-bk1/sound/isa/gus/interwave.c linux-2.5.65-bk2/sound/isa/gus/interwave.c
--- linux-2.5.65-bk1/sound/isa/gus/interwave.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/sound/isa/gus/interwave.c	Mon Mar 31 12:39:51 2003
@@ -148,12 +148,12 @@
 #define ISAPNP_INTERWAVE(_va, _vb, _vc, _device, _audio) \
 	{ \
 		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		devs : { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), } \
+		.devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), } \
 	}
 #define ISAPNP_INTERWAVE_STB(_va, _vb, _vc, _device, _audio, _tone) \
 	{ \
 		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		devs : { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
+		.devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
 			 ISAPNP_DEVICE_ID(_va, _vb, _vc, _tone), } \
 	}
 
diff -urN linux-2.5.65-bk1/sound/isa/opti9xx/opti92x-ad1848.c linux-2.5.65-bk2/sound/isa/opti9xx/opti92x-ad1848.c
--- linux-2.5.65-bk1/sound/isa/opti9xx/opti92x-ad1848.c	Mon Mar 17 13:43:44 2003
+++ linux-2.5.65-bk2/sound/isa/opti9xx/opti92x-ad1848.c	Mon Mar 31 12:39:51 2003
@@ -987,9 +987,11 @@
 			s = s->link_next;
 		} while (s != substream);
 		spin_lock(&chip->lock);
-		if (cmd == SNDRV_PCM_TRIGGER_START)
+		if (cmd == SNDRV_PCM_TRIGGER_START) {
 			snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what);
-		else
+			if (what & OPTi93X_CAPTURE_ENABLE)
+				udelay(50);
+		} else
 			snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00);
 		spin_unlock(&chip->lock);
 		break;
@@ -1207,6 +1209,7 @@
 		return error;
 	runtime->hw = snd_opti93x_capture;
 	snd_pcm_set_sync(substream);
+	chip->capture_substream = substream;
 	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
 	return error;
diff -urN linux-2.5.65-bk1/sound/isa/sb/es968.c linux-2.5.65-bk2/sound/isa/sb/es968.c
--- linux-2.5.65-bk1/sound/isa/sb/es968.c	Mon Mar 17 13:44:06 2003
+++ linux-2.5.65-bk2/sound/isa/sb/es968.c	Mon Mar 31 12:39:51 2003
@@ -277,7 +277,7 @@
 #ifndef MODULE
 
 /* format is: snd-es968=enable,index,id,
-			port,irq,snd_dma1 */
+			port,irq,dma1 */
 
 static int __init alsa_card_es968_setup(char *str)
 {
diff -urN linux-2.5.65-bk1/sound/isa/sb/sb16.c linux-2.5.65-bk2/sound/isa/sb/sb16.c
--- linux-2.5.65-bk1/sound/isa/sb/sb16.c	Mon Mar 17 13:44:39 2003
+++ linux-2.5.65-bk2/sound/isa/sb/sb16.c	Mon Mar 31 12:39:51 2003
@@ -168,12 +168,12 @@
 #define ISAPNP_SB16(_va, _vb, _vc, _device, _audio) \
 	{ \
 		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		devs : { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), } \
+		.devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), } \
 	}
 #define ISAPNP_SBAWE(_va, _vb, _vc, _device, _audio, _awe) \
 	{ \
 		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		devs : { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
+		.devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
 			 ISAPNP_DEVICE_ID(_va, _vb, _vc, _awe), } \
 	}
 
@@ -636,9 +636,9 @@
 #ifdef MODULE
 		printk(KERN_ERR "Sound Blaster 16 soundcard not found or device busy\n");
 #ifdef SNDRV_SBAWE_EMU8000
-		printk(KERN_ERR "In case, if you have non-AWE card, try snd-card-sb16 module\n");
+		printk(KERN_ERR "In case, if you have non-AWE card, try snd-sb16 module\n");
 #else
-		printk(KERN_ERR "In case, if you have AWE card, try snd-card-sbawe module\n");
+		printk(KERN_ERR "In case, if you have AWE card, try snd-sbawe module\n");
 #endif
 #endif
 		return -ENODEV;
diff -urN linux-2.5.65-bk1/sound/isa/sb/sb16_csp.c linux-2.5.65-bk2/sound/isa/sb/sb16_csp.c
--- linux-2.5.65-bk1/sound/isa/sb/sb16_csp.c	Mon Mar 17 13:44:49 2003
+++ linux-2.5.65-bk2/sound/isa/sb/sb16_csp.c	Mon Mar 31 12:39:51 2003
@@ -213,7 +213,10 @@
 		info.run_width = p->run_width;
 		info.version = p->version;
 		info.state = p->running;
-		err = copy_to_user((void *) arg, &info, sizeof(info));
+		if (copy_to_user((void *) arg, &info, sizeof(info)))
+			err = -EFAULT;
+		else
+			err = 0;
 		break;
 
 		/* load CSP microcode */
diff -urN linux-2.5.65-bk1/sound/isa/sb/sb8.c linux-2.5.65-bk2/sound/isa/sb/sb8.c
--- linux-2.5.65-bk1/sound/isa/sb/sb8.c	Mon Mar 17 13:44:17 2003
+++ linux-2.5.65-bk2/sound/isa/sb/sb8.c	Mon Mar 31 12:39:51 2003
@@ -123,10 +123,10 @@
 	if (chip->hardware >= SB_HW_16) {
 		snd_card_free(card);
 		if (chip->hardware == SB_HW_ALS100)
-			snd_printdd("ALS100 chip detected at 0x%lx, try snd-card-als100 module\n",
+			snd_printdd("ALS100 chip detected at 0x%lx, try snd-als100 module\n",
 				    port[dev]);
 		else
-			snd_printdd("SB 16 chip detected at 0x%lx, try snd-card-sb16 module\n",
+			snd_printdd("SB 16 chip detected at 0x%lx, try snd-sb16 module\n",
 				    port[dev]);
 		return -ENODEV;
 	}
diff -urN linux-2.5.65-bk1/sound/isa/sb/sb8_main.c linux-2.5.65-bk2/sound/isa/sb/sb8_main.c
--- linux-2.5.65-bk1/sound/isa/sb/sb8_main.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/sound/isa/sb/sb8_main.c	Mon Mar 31 12:39:51 2003
@@ -97,7 +97,7 @@
 {
 	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 	if (r->min > SB8_RATE(22050) || r->max <= SB8_RATE(11025)) {
-		snd_interval_t t = { min: 1, max: 1 };
+		snd_interval_t t = { .min = 1, .max = 1 };
 		return snd_interval_refine(hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS), &t);
 	}
 	return 0;
diff -urN linux-2.5.65-bk1/sound/isa/sgalaxy.c linux-2.5.65-bk2/sound/isa/sgalaxy.c
--- linux-2.5.65-bk1/sound/isa/sgalaxy.c	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/sound/isa/sgalaxy.c	Mon Mar 31 12:39:51 2003
@@ -44,7 +44,7 @@
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
 static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240 */
 static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x530,0xe80,0xf40,0x604 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 7,9,10,11 */
@@ -300,7 +300,7 @@
 {
 	int dev, cards;
 
-	for (dev = cards = 0; dev < SNDRV_CARDS && snd_enable[dev]; dev++) {
+	for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
 		if (snd_sgalaxy_probe(dev) >= 0)
 			cards++;
 	}
@@ -327,7 +327,7 @@
 
 #ifndef MODULE
 
-/* format is: snd-sgalaxy=snd_enable,index,id,
+/* format is: snd-sgalaxy=enable,index,id,
 			  sbport,wssport,
 			  irq,dma1 */
 
@@ -337,7 +337,7 @@
 
 	if (nr_dev >= SNDRV_CARDS)
 		return 0;
-	(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
+	(void)(get_option(&str,&enable[nr_dev]) == 2 &&
 	       get_option(&str,&index[nr_dev]) == 2 &&
 	       get_id(&str,&id[nr_dev]) == 2 &&
 	       get_option(&str,(int *)&sbport[nr_dev]) == 2 &&
diff -urN linux-2.5.65-bk1/sound/oss/gus_midi.c linux-2.5.65-bk2/sound/oss/gus_midi.c
--- linux-2.5.65-bk1/sound/oss/gus_midi.c	Mon Mar 17 13:44:50 2003
+++ linux-2.5.65-bk2/sound/oss/gus_midi.c	Mon Mar 31 12:39:51 2003
@@ -179,7 +179,7 @@
 		qhead++;
 	}
 	spin_unlock_irqrestore(&lock,flags);
-	return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
+	return (qlen > 0) || !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
 }
 
 #define MIDI_SYNTH_NAME	"Gravis Ultrasound Midi"
diff -urN linux-2.5.65-bk1/sound/pci/Kconfig linux-2.5.65-bk2/sound/pci/Kconfig
--- linux-2.5.65-bk1/sound/pci/Kconfig	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/sound/pci/Kconfig	Mon Mar 31 12:39:51 2003
@@ -149,6 +149,15 @@
 	  Delta 66/44, Audiophile 24/96; Hoontech SoundTrack DSP 24 (Value);
 	  TerraTec - EWX 24/96, EWS 88MT, EWS 88D, DMX 6Fire.
 
+config SND_ICE1724
+	tristate "ICE/VT1724 (Envy24HT)"
+	depends on SND
+	help
+	  Say 'Y' or 'M' to include support for ICE/VT1724 (Envy24HT) based
+	  soundcards.
+	  Currently supported hardware is: MidiMan M Audio - Revolution 7.1,
+	  AMP Ltd AUDIO2000.
+
 config SND_INTEL8X0
 	tristate "Intel i8x0/MX440, SiS 7012; Ali 5455; NForce Audio; AMD768/8111"
 	depends on SND
diff -urN linux-2.5.65-bk1/sound/pci/ac97/ac97_codec.c linux-2.5.65-bk2/sound/pci/ac97/ac97_codec.c
--- linux-2.5.65-bk1/sound/pci/ac97/ac97_codec.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/sound/pci/ac97/ac97_codec.c	Mon Mar 31 12:39:51 2003
@@ -51,115 +51,115 @@
 
  */
 
-static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97);
+static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix);
 
 typedef struct {
 	unsigned int id;
 	unsigned int mask;
-	char *name;
+	const char *name;
 	int (*patch)(ac97_t *ac97);
+	int (*mpatch)(ac97_t *ac97);
 } ac97_codec_id_t;
 
 static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = {
-{ 0x414b4d00, 0xffffff00, "Asahi Kasei",	NULL },
-{ 0x41445300, 0xffffff00, "Analog Devices",	NULL },
-{ 0x414c4300, 0xffffff00, "Realtek",		NULL },
-{ 0x414c4700, 0xffffff00, "Avance Logic",	NULL },
-{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL },
-{ 0x43525900, 0xffffff00, "Cirrus Logic",	NULL },
-{ 0x43585400, 0xffffff00, "Conexant",           NULL },
-{ 0x44543000, 0xffffff00, "Diamond Technology", NULL },
-{ 0x454d4300, 0xffffff00, "eMicro",		NULL },
-{ 0x45838300, 0xffffff00, "ESS Technology",	NULL },
-{ 0x48525300, 0xffffff00, "Intersil",		NULL },
-{ 0x49434500, 0xffffff00, "ICEnsemble",		NULL },
-{ 0x49544500, 0xffffff00, "ITE Tech.Inc",	NULL },
-{ 0x4e534300, 0xffffff00, "National Semiconductor", NULL },
-{ 0x50534300, 0xffffff00, "Philips",		NULL },
-{ 0x53494c00, 0xffffff00, "Silicon Laboratory",	NULL },
-{ 0x54524100, 0xffffff00, "TriTech",		NULL },
-{ 0x54584e00, 0xffffff00, "Texas Instruments",	NULL },
-{ 0x56494100, 0xffffff00, "VIA Technologies",   NULL },
-{ 0x57454300, 0xffffff00, "Winbond",		NULL },
-{ 0x574d4c00, 0xffffff00, "Wolfson",		NULL },
-{ 0x594d4800, 0xffffff00, "Yamaha",		NULL },
-{ 0x83847600, 0xffffff00, "SigmaTel",		NULL },
-{ 0,	      0, 	  NULL,			NULL }
+{ 0x414b4d00, 0xffffff00, "Asahi Kasei",	NULL,	NULL },
+{ 0x41445300, 0xffffff00, "Analog Devices",	NULL,	NULL },
+{ 0x414c4300, 0xffffff00, "Realtek",		NULL,	NULL },
+{ 0x414c4700, 0xffffff00, "Avance Logic",	NULL,	NULL },
+{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL,	NULL },
+{ 0x43525900, 0xffffff00, "Cirrus Logic",	NULL,	NULL },
+{ 0x43585400, 0xffffff00, "Conexant",           NULL,	NULL },
+{ 0x44543000, 0xffffff00, "Diamond Technology", NULL,	NULL },
+{ 0x454d4300, 0xffffff00, "eMicro",		NULL,	NULL },
+{ 0x45838300, 0xffffff00, "ESS Technology",	NULL,	NULL },
+{ 0x48525300, 0xffffff00, "Intersil",		NULL,	NULL },
+{ 0x49434500, 0xffffff00, "ICEnsemble",		NULL,	NULL },
+{ 0x49544500, 0xffffff00, "ITE Tech.Inc",	NULL,	NULL },
+{ 0x4e534300, 0xffffff00, "National Semiconductor", NULL, NULL },
+{ 0x50534300, 0xffffff00, "Philips",		NULL,	NULL },
+{ 0x53494c00, 0xffffff00, "Silicon Laboratory",	NULL,	NULL },
+{ 0x54524100, 0xffffff00, "TriTech",		NULL,	NULL },
+{ 0x54584e00, 0xffffff00, "Texas Instruments",	NULL,	NULL },
+{ 0x56494100, 0xffffff00, "VIA Technologies",   NULL,	NULL },
+{ 0x57454300, 0xffffff00, "Winbond",		NULL,	NULL },
+{ 0x574d4c00, 0xffffff00, "Wolfson",		NULL,	NULL },
+{ 0x594d4800, 0xffffff00, "Yamaha",		NULL,	NULL },
+{ 0x83847600, 0xffffff00, "SigmaTel",		NULL,	NULL },
+{ 0,	      0, 	  NULL,			NULL,	NULL }
 };
 
 static const ac97_codec_id_t snd_ac97_codec_ids[] = {
-{ 0x014b0502, 0xffffffff, "NM256AV",		NULL }, // FIXME: which real one?
-{ 0x414b4d00, 0xffffffff, "AK4540",		NULL },
-{ 0x414b4d01, 0xffffffff, "AK4542",		NULL },
-{ 0x414b4d02, 0xffffffff, "AK4543",		NULL },
-{ 0x414b4d06, 0xffffffff, "AK4544A",		NULL },
-{ 0x414b4d07, 0xffffffff, "AK4545",		NULL },
-{ 0x41445303, 0xffffffff, "AD1819",		patch_ad1819 },
-{ 0x41445340, 0xffffffff, "AD1881",		patch_ad1881 },
-{ 0x41445348, 0xffffffff, "AD1881A",		patch_ad1881 },
-{ 0x41445360, 0xffffffff, "AD1885",		patch_ad1885 },
-{ 0x41445361, 0xffffffff, "AD1886",		patch_ad1886 },
-{ 0x41445362, 0xffffffff, "AD1887",		patch_ad1881 },
-{ 0x41445363, 0xffffffff, "AD1886A",		patch_ad1881 },
-{ 0x41445370, 0xffffffff, "AD1980",		patch_ad1980 },
-{ 0x41445372, 0xffffffff, "AD1981A",		patch_ad1881 },
-{ 0x414c4300, 0xfffffff0, "RL5306",	 	NULL },
-{ 0x414c4310, 0xfffffff0, "RL5382", 		NULL },
-{ 0x414c4320, 0xfffffff0, "RL5383", 		NULL },
-{ 0x414c4710, 0xfffffff0, "ALC200/200P",	NULL },
-{ 0x414c4720, 0xfffffff0, "ALC650",		patch_alc650 },
-{ 0x414c4730, 0xffffffff, "ALC101",		NULL },
-{ 0x414c4740, 0xfffffff0, "ALC202",		NULL },
-{ 0x414c4750, 0xfffffff0, "ALC250",		NULL },
-{ 0x434d4941, 0xffffffff, "CMI9738",		NULL },
-{ 0x434d4961, 0xffffffff, "CMI9739",		NULL },
-{ 0x43525900, 0xfffffff8, "CS4297",		NULL },
-{ 0x43525910, 0xfffffff8, "CS4297A",		patch_cirrus_spdif },
-{ 0x43525920, 0xfffffff8, "CS4294/4298",	NULL },
-{ 0x43525928, 0xfffffff8, "CS4294",		NULL },
-{ 0x43525930, 0xfffffff8, "CS4299",		patch_cirrus_cs4299 },
-{ 0x43525948, 0xfffffff8, "CS4201",		NULL },
-{ 0x43525958, 0xfffffff8, "CS4205",		patch_cirrus_spdif },
-{ 0x43525960, 0xfffffff8, "CS4291",		NULL },
-{ 0x43585421, 0xffffffff, "HSD11246",		NULL },	// SmartMC II
-{ 0x43585428, 0xfffffff8, "Cx20468",		patch_conexant }, // SmartAMC fixme: the mask might be different
-{ 0x44543031, 0xfffffff0, "DT0398",		NULL },
-{ 0x454d4328, 0xffffffff, "28028",		NULL },  // same as TR28028?
-{ 0x45838308, 0xffffffff, "ESS1988",		NULL },
-{ 0x48525300, 0xffffff00, "HMP9701",		NULL },
-{ 0x49434501, 0xffffffff, "ICE1230",		NULL },
-{ 0x49434511, 0xffffffff, "ICE1232",		NULL }, // alias VIA VT1611A?
-{ 0x49434551, 0xffffffff, "VT1616", 		NULL }, 
-{ 0x49544520, 0xffffffff, "IT2226E",		NULL },
-{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48",	NULL }, // only guess --jk
-{ 0x4e534331, 0xffffffff, "LM4549",		NULL },
-{ 0x50534304, 0xffffffff, "UCB1400",		NULL },
-{ 0x53494c22, 0xffffffff, "Si3036",		NULL },
-{ 0x53494c23, 0xffffffff, "Si3038",		NULL },
-{ 0x54524102, 0xffffffff, "TR28022",		NULL },
-{ 0x54524106, 0xffffffff, "TR28026",		NULL },
-{ 0x54524108, 0xffffffff, "TR28028",		patch_tritech_tr28028 }, // added by xin jin [07/09/99]
-{ 0x54524123, 0xffffffff, "TR28602",		NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
-{ 0x54584e20, 0xffffffff, "TLC320AD9xC",	NULL },
-{ 0x56494161, 0xffffffff, "VIA1612A",		NULL }, // modified ICE1232 with S/PDIF
-{ 0x57454301, 0xffffffff, "W83971D",		NULL },
-{ 0x574d4c00, 0xffffffff, "WM9701A",		patch_wolfson00 },
-{ 0x574d4c03, 0xffffffff, "WM9703/9707",	patch_wolfson03 },
-{ 0x574d4c04, 0xffffffff, "WM9704/quad",	patch_wolfson04 },
-{ 0x574d4c05, 0xffffffff, "WM9705",		NULL },	// patch?
-{ 0x594d4800, 0xffffffff, "YMF743",		NULL },
-{ 0x594d4802, 0xffffffff, "YMF752",		NULL },
-{ 0x594d4803, 0xffffffff, "YMF753",		patch_yamaha_ymf753 },
-{ 0x83847600, 0xffffffff, "STAC9700/83/84",	NULL },
-{ 0x83847604, 0xffffffff, "STAC9701/3/4/5",	NULL },
-{ 0x83847605, 0xffffffff, "STAC9704",		NULL },
-{ 0x83847608, 0xffffffff, "STAC9708/11",	patch_sigmatel_stac9708 },
-{ 0x83847609, 0xffffffff, "STAC9721/23",	patch_sigmatel_stac9721 },
-{ 0x83847644, 0xffffffff, "STAC9744",		patch_sigmatel_stac9744 },
-{ 0x83847650, 0xffffffff, "STAC9750/51",	NULL },	// patch?
-{ 0x83847656, 0xffffffff, "STAC9756/57",	patch_sigmatel_stac9756 },
-{ 0x83847666, 0xffffffff, "STAC9766/67",	NULL }, // patch?
-{ 0, 	      0,	  NULL,			NULL }
+{ 0x014b0502, 0xffffffff, "NM256AV",		NULL,		NULL }, // FIXME: which real one?
+{ 0x414b4d00, 0xffffffff, "AK4540",		NULL,		NULL },
+{ 0x414b4d01, 0xffffffff, "AK4542",		NULL,		NULL },
+{ 0x414b4d02, 0xffffffff, "AK4543",		NULL,		NULL },
+{ 0x414b4d06, 0xffffffff, "AK4544A",		NULL,		NULL },
+{ 0x414b4d07, 0xffffffff, "AK4545",		NULL,		NULL },
+{ 0x41445303, 0xffffffff, "AD1819",		patch_ad1819,	NULL },
+{ 0x41445340, 0xffffffff, "AD1881",		patch_ad1881,	NULL },
+{ 0x41445348, 0xffffffff, "AD1881A",		patch_ad1881,	NULL },
+{ 0x41445360, 0xffffffff, "AD1885",		patch_ad1885,	NULL },
+{ 0x41445361, 0xffffffff, "AD1886",		patch_ad1886,	NULL },
+{ 0x41445362, 0xffffffff, "AD1887",		patch_ad1881,	NULL },
+{ 0x41445363, 0xffffffff, "AD1886A",		patch_ad1881,	NULL },
+{ 0x41445370, 0xffffffff, "AD1980",		patch_ad1980,	NULL },
+{ 0x41445372, 0xffffffff, "AD1981A",		patch_ad1881,	NULL },
+{ 0x414c4300, 0xfffffff0, "RL5306",	 	NULL,		NULL },
+{ 0x414c4310, 0xfffffff0, "RL5382", 		NULL,		NULL },
+{ 0x414c4320, 0xfffffff0, "RL5383", 		NULL,		NULL },
+{ 0x414c4710, 0xfffffff0, "ALC200/200P",	NULL,		NULL },
+{ 0x414c4720, 0xfffffff0, "ALC650",		patch_alc650,	NULL },
+{ 0x414c4730, 0xffffffff, "ALC101",		NULL,		NULL },
+{ 0x414c4740, 0xfffffff0, "ALC202",		NULL,		NULL },
+{ 0x414c4750, 0xfffffff0, "ALC250",		NULL,		NULL },
+{ 0x434d4941, 0xffffffff, "CMI9738",		NULL,		NULL },
+{ 0x434d4961, 0xffffffff, "CMI9739",		NULL,		NULL },
+{ 0x43525900, 0xfffffff8, "CS4297",		NULL,		NULL },
+{ 0x43525910, 0xfffffff8, "CS4297A",		patch_cirrus_spdif,	NULL },
+{ 0x43525920, 0xfffffff8, "CS4294/4298",	NULL,		NULL },
+{ 0x43525928, 0xfffffff8, "CS4294",		NULL,		NULL },
+{ 0x43525930, 0xfffffff8, "CS4299",		patch_cirrus_cs4299,	NULL },
+{ 0x43525948, 0xfffffff8, "CS4201",		NULL,		NULL },
+{ 0x43525958, 0xfffffff8, "CS4205",		patch_cirrus_spdif,	NULL },
+{ 0x43525960, 0xfffffff8, "CS4291",		NULL,		NULL },
+{ 0x43585421, 0xffffffff, "HSD11246",		NULL,		NULL },	// SmartMC II
+{ 0x43585428, 0xfffffff8, "Cx20468",		patch_conexant,	NULL }, // SmartAMC fixme: the mask might be different
+{ 0x44543031, 0xfffffff0, "DT0398",		NULL,		NULL },
+{ 0x454d4328, 0xffffffff, "28028",		NULL,		NULL },  // same as TR28028?
+{ 0x45838308, 0xffffffff, "ESS1988",		NULL,		NULL },
+{ 0x48525300, 0xffffff00, "HMP9701",		NULL,		NULL },
+{ 0x49434501, 0xffffffff, "ICE1230",		NULL,		NULL },
+{ 0x49434511, 0xffffffff, "ICE1232",		NULL,		NULL }, // alias VIA VT1611A?
+{ 0x49434551, 0xffffffff, "VT1616", 		NULL,		NULL }, 
+{ 0x49544520, 0xffffffff, "IT2226E",		NULL,		NULL },
+{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48",	NULL,		NULL }, // only guess --jk
+{ 0x4e534331, 0xffffffff, "LM4549",		NULL,		NULL },
+{ 0x50534304, 0xffffffff, "UCB1400",		NULL,		NULL },
+{ 0x53494c20, 0xffffffe0, "Si3036/8",		NULL,		NULL },
+{ 0x54524102, 0xffffffff, "TR28022",		NULL,		NULL },
+{ 0x54524106, 0xffffffff, "TR28026",		NULL,		NULL },
+{ 0x54524108, 0xffffffff, "TR28028",		patch_tritech_tr28028,	NULL }, // added by xin jin [07/09/99]
+{ 0x54524123, 0xffffffff, "TR28602",		NULL,		NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
+{ 0x54584e20, 0xffffffff, "TLC320AD9xC",	NULL,		NULL },
+{ 0x56494161, 0xffffffff, "VIA1612A",		NULL,		NULL }, // modified ICE1232 with S/PDIF
+{ 0x57454301, 0xffffffff, "W83971D",		NULL,		NULL },
+{ 0x574d4c00, 0xffffffff, "WM9701A",		patch_wolfson00,NULL },
+{ 0x574d4c03, 0xffffffff, "WM9703/9707",	patch_wolfson03,NULL },
+{ 0x574d4c04, 0xffffffff, "WM9704/quad",	patch_wolfson04,NULL },
+{ 0x574d4c05, 0xffffffff, "WM9705",		NULL,		NULL },	// patch?
+{ 0x594d4800, 0xffffffff, "YMF743",		NULL,		NULL },
+{ 0x594d4802, 0xffffffff, "YMF752",		NULL,		NULL },
+{ 0x594d4803, 0xffffffff, "YMF753",		patch_yamaha_ymf753,	NULL },
+{ 0x83847600, 0xffffffff, "STAC9700/83/84",	NULL,		NULL },
+{ 0x83847604, 0xffffffff, "STAC9701/3/4/5",	NULL,		NULL },
+{ 0x83847605, 0xffffffff, "STAC9704",		NULL,		NULL },
+{ 0x83847608, 0xffffffff, "STAC9708/11",	patch_sigmatel_stac9708,	NULL },
+{ 0x83847609, 0xffffffff, "STAC9721/23",	patch_sigmatel_stac9721,	NULL },
+{ 0x83847644, 0xffffffff, "STAC9744",		patch_sigmatel_stac9744,	NULL },
+{ 0x83847650, 0xffffffff, "STAC9750/51",	NULL,		NULL },	// patch?
+{ 0x83847656, 0xffffffff, "STAC9756/57",	patch_sigmatel_stac9756,	NULL },
+{ 0x83847666, 0xffffffff, "STAC9766/67",	NULL,		NULL }, // patch?
+{ 0, 	      0,	  NULL,			NULL,		NULL }
 };
 
 static const char *snd_ac97_stereo_enhancements[] =
@@ -325,7 +325,7 @@
  * Compares the value with the register cache and updates the value
  * only when the value is changed.
  *
- * Retruns 1 if the value is changed, 0 if no change, or a negative
+ * Returns 1 if the value is changed, 0 if no change, or a negative
  * code on failure.
  */
 int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
@@ -352,7 +352,7 @@
  * @mask: the bit-mask to change
  * @value: the value to set
  *
- * Updates the masked-bits on the given register onle when the value
+ * Updates the masked-bits on the given register only when the value
  * is changed.
  *
  * Returns 1 if the bits are changed, 0 if no change, or a negative
@@ -1022,6 +1022,50 @@
 AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31)
 };
 
+static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[2] = { "AC-Link", "A/D Converter" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	val = ac97->regs[AC97_AD_SERIAL_CFG];
+	ucontrol->value.enumerated.item[0] = (val >> 2) & 1;
+	return 0;
+}
+
+static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	if (ucontrol->value.enumerated.item[0] > 1)
+		return -EINVAL;
+	val = ucontrol->value.enumerated.item[0] << 2;
+	return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val);
+}
+
+static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source =
+	{
+		iface: SNDRV_CTL_ELEM_IFACE_MIXER,
+		name: SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		info: snd_ac97_ad1980_spdif_source_info,
+		get: snd_ac97_ad1980_spdif_source_get,
+		put: snd_ac97_ad1980_spdif_source_put,
+	};
+
+
 /*
  * ALC650
  */
@@ -1032,11 +1076,12 @@
 	AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0),
 	/* 4: Analog Input To Surround */
 	/* 5: Analog Input To Center/LFE */
-	/* 6: Indepedent Master Volume Right */
-	/* 7: Indepedent Master Volume Left */
+	/* 6: Independent Master Volume Right */
+	/* 7: Independent Master Volume Left */
 	/* 8: reserved */
 	AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
 	AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0),
+	AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),
 #if 0 /* always set in patch_alc650 */
 	AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
 	AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
@@ -1097,11 +1142,11 @@
 
 static const snd_kcontrol_new_t snd_ac97_ymf753_controls_speaker =
 {
-	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
-	name: "3D Control - Speaker",
-	info: snd_ac97_ymf753_info_speaker,
-	get: snd_ac97_ymf753_get_speaker,
-	put: snd_ac97_ymf753_put_speaker,
+	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name	= "3D Control - Speaker",
+	.info	= snd_ac97_ymf753_info_speaker,
+	.get	= snd_ac97_ymf753_get_speaker,
+	.put	= snd_ac97_ymf753_put_speaker,
 };
 
 /* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */
@@ -1140,7 +1185,7 @@
 }
 
 /* The AC'97 spec states that the S/PDIF signal is to be output at pin 48.
-   The YMF753 will ouput the S/PDIF signal to pin 43, 47 (EAPD), or 48.
+   The YMF753 will output the S/PDIF signal to pin 43, 47 (EAPD), or 48.
    By default, no output pin is selected, and the S/PDIF signal is not output.
    There is also a bit to mute S/PDIF output in a vendor-specific register. */
 static int snd_ac97_ymf753_spdif_output_pin_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
@@ -1182,18 +1227,18 @@
 
 static const snd_kcontrol_new_t snd_ac97_ymf753_controls_spdif[3] = {
 	{
-		iface: SNDRV_CTL_ELEM_IFACE_MIXER,
-		name: SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		info: snd_ac97_ymf753_spdif_source_info,
-		get: snd_ac97_ymf753_spdif_source_get,
-		put: snd_ac97_ymf753_spdif_source_put,
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		.info	= snd_ac97_ymf753_spdif_source_info,
+		.get	= snd_ac97_ymf753_spdif_source_get,
+		.put	= snd_ac97_ymf753_spdif_source_put,
 	},
 	{
-		iface: SNDRV_CTL_ELEM_IFACE_MIXER,
-		name: SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Output Pin",
-		info: snd_ac97_ymf753_spdif_output_pin_info,
-		get: snd_ac97_ymf753_spdif_output_pin_get,
-		put: snd_ac97_ymf753_spdif_output_pin_put,
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Output Pin",
+		.info	= snd_ac97_ymf753_spdif_output_pin_info,
+		.get	= snd_ac97_ymf753_spdif_output_pin_get,
+		.put	= snd_ac97_ymf753_spdif_output_pin_put,
 	},
 	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1)
 };
@@ -1680,6 +1725,9 @@
 				for (idx = 0; idx < 3; idx++)
 					if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_spdif[idx], ac97))) < 0)
 						return err;
+			} else if (ac97->id == AC97_ID_AD1980) {
+				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ad1980_spdif_source, ac97))) < 0)
+					return err;
 			}
 			/* set default PCM S/PDIF params */
 			/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
@@ -1735,6 +1783,12 @@
 	return 0;
 }
 
+static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97)
+{
+	/* TODO */
+	return 0;
+}
+
 static int snd_ac97_test_rate(ac97_t *ac97, int reg, int rate)
 {
 	unsigned short val;
@@ -1771,7 +1825,7 @@
 	*r_result = result;
 }
 
-static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name)
+static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem)
 {
 	const ac97_codec_id_t *pid;
 
@@ -1782,8 +1836,12 @@
 	for (pid = snd_ac97_codec_id_vendors; pid->id; pid++)
 		if (pid->id == (id & pid->mask)) {
 			strcpy(name, pid->name);
-			if (ac97 && pid->patch)
-				pid->patch(ac97);
+			if (ac97) {
+				if (!modem && pid->patch)
+					pid->patch(ac97);
+				else if (modem && pid->mpatch)
+					pid->mpatch(ac97);
+			} 
 			goto __vendor_ok;
 		}
 	return;
@@ -1795,8 +1853,12 @@
 			strcat(name, pid->name);
 			if (pid->mask != 0xffffffff)
 				sprintf(name + strlen(name), " rev %d", id & ~pid->mask);
-			if (ac97 && pid->patch)
-				pid->patch(ac97);
+			if (ac97) {
+				if (!modem && pid->patch)
+					pid->patch(ac97);
+				else if (modem && pid->mpatch)
+					pid->mpatch(ac97);
+			}
 			return;
 		}
 	sprintf(name + strlen(name), " id %x", id & 0xff);
@@ -1808,7 +1870,7 @@
  */
 static int ac97_reset_wait(ac97_t *ac97, int timeout, int with_modem)
 {
-	unsigned long end_time;
+	signed long end_time;
 	end_time = jiffies + timeout;
 	do {
 		unsigned short ext_mid;
@@ -1850,7 +1912,7 @@
  * The template must include the valid callbacks (at least read and
  * write), the codec number (num) and address (addr), and the private
  * data (private_data).  The other callbacks, wait and reset, are not
- * mandantory.
+ * mandatory.
  * 
  * The clock is set to 48000.  If another clock is needed, reset
  * ac97->clock manually afterwards.
@@ -1858,15 +1920,17 @@
  * The ac97 instance is registered as a low-level device, so you don't
  * have to release it manually.
  *
- * Returns zero if sucessful, or a negative error code on failure.
+ * The MCs (Modem Codecs only) are only detected but valid. The PCM driver
+ * have to check for MCs using the !ac97_is_audio() function.
+ *
+ * Returns zero if successful, or a negative error code on failure.
  */
-
 int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
 {
 	int err;
 	ac97_t *ac97;
 	char name[64];
-	unsigned long end_time;
+	signed long end_time;
 	static snd_device_ops_t ops = {
 		.dev_free =	snd_ac97_dev_free,
 	};
@@ -1929,8 +1993,8 @@
 		goto __ready_ok;
 
 	/* FIXME: add powerdown control */
-	/* nothing should be in powerdown mode */
-	if (ac97->scaps & AC97_SCAP_AUDIO) {
+	if (ac97_is_audio(ac97)) {
+		/* nothing should be in powerdown mode */
 		snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
 		snd_ac97_write_cache_test(ac97, AC97_RESET, 0);		/* reset to defaults */
 		udelay(100);
@@ -1950,7 +2014,7 @@
       __ready_ok:
 	if (ac97->clock == 0)
 		ac97->clock = 48000;	/* standard value */
-	if (ac97->scaps & AC97_SCAP_AUDIO)
+	if (ac97_is_audio(ac97))
 		ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT;
 	else
 		ac97->addr = (ac97->ext_mid & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT;
@@ -1985,33 +2049,216 @@
 	/* additional initializations */
 	if (ac97->init)
 		ac97->init(ac97);
-	snd_ac97_get_name(ac97, ac97->id, name);
-	snd_ac97_get_name(NULL, ac97->id, name);  // ac97->id might be changed in the special setup code
-	if (card->mixername[0] == '\0') {
-		strcpy(card->mixername, name);
-	} else {
-		if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {
-			strcat(card->mixername, ",");
-			strcat(card->mixername, name);
+	snd_ac97_get_name(ac97, ac97->id, name, 0);
+	snd_ac97_get_name(NULL, ac97->id, name, 0);  // ac97->id might be changed in the special setup code
+	if (ac97_is_audio(ac97)) {
+		if (card->mixername[0] == '\0') {
+			strcpy(card->mixername, name);
+		} else {
+			if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {
+				strcat(card->mixername, ",");
+				strcat(card->mixername, name);
+			}
 		}
-	}
-	if (ac97->scaps & AC97_SCAP_AUDIO) {
 		if ((err = snd_component_add(card, "AC97a")) < 0) {
 			snd_ac97_free(ac97);
 			return err;
 		}
 	}
+	if (ac97_is_audio(ac97) && snd_ac97_mixer_build(card, ac97) < 0) {
+		snd_ac97_free(ac97);
+		return -ENOMEM;
+	}
+	snd_ac97_proc_init(card, ac97, "ac97");
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) {
+		snd_ac97_free(ac97);
+		return err;
+	}
+	*rac97 = ac97;
+	return 0;
+}
+
+/* wait for a while until registers are accessible after RESET
+ * return 0 if ok, negative not ready
+ */
+static int ac97_modem_reset_wait(ac97_t *ac97, int timeout)
+{
+	signed long end_time;
+	end_time = jiffies + timeout;
+	do {
+		unsigned short ext_mid;
+		
+		/* use preliminary reads to settle the communication */
+		snd_ac97_read(ac97, AC97_EXTENDED_MID);
+		snd_ac97_read(ac97, AC97_VENDOR_ID1);
+		snd_ac97_read(ac97, AC97_VENDOR_ID2);
+		ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);
+		if (ext_mid != 0xffff && (ext_mid & 1) != 0)
+			return 0;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
+	} while (time_after_eq(end_time, jiffies));
+	return -ENODEV;
+}
+
+/**
+ * snd_ac97_modem - create an MC97 codec component
+ * @card: the card instance
+ * @_ac97: the template of ac97, including index, callbacks and
+ *         the private data.
+ * @rac97: the pointer to store the new ac97 instance.
+ *
+ * Creates an MC97 codec component.  An ac97_t instance is newly
+ * allocated and initialized from the template (_ac97).  The codec
+ * is then initialized by the standard procedure.
+ *
+ * The template must include the valid callbacks (at least read and
+ * write), the codec number (num) and address (addr), and the private
+ * data (private_data).  The other callbacks, wait and reset, are not
+ * mandatory.
+ * 
+ * The clock is set to 48000.  If another clock is needed, reset
+ * ac97->clock manually afterwards.
+ *
+ * The ac97 instance is registered as a low-level device, so you don't
+ * have to release it manually.
+ *
+ * The ACs (Audio Codecs only) are only detected but valid. The PCM driver
+ * have to check for ACs using the !ac97_is_modem() function.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ */
+int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
+{
+	int err;
+	ac97_t *ac97;
+	char name[64];
+	unsigned long end_time;
+	unsigned short tmp;
+	static snd_device_ops_t ops = {
+		.dev_free =	snd_ac97_dev_free,
+	};
+
+	snd_assert(rac97 != NULL, return -EINVAL);
+	*rac97 = NULL;
+	snd_assert(card != NULL && _ac97 != NULL, return -EINVAL);
+	ac97 = snd_magic_kcalloc(ac97_t, 0, GFP_KERNEL);
+	if (ac97 == NULL)
+		return -ENOMEM;
+	*ac97 = *_ac97;
+	ac97->card = card;
+	spin_lock_init(&ac97->reg_lock);
+
+	if (ac97->reset) {
+		ac97->reset(ac97);
+		goto __access_ok;
+	}
+
+	snd_ac97_write(ac97, AC97_EXTENDED_MID, 0);	/* reset to defaults */
+	if (ac97->wait)
+		ac97->wait(ac97);
+	else {
+		udelay(50);
+		if (ac97_modem_reset_wait(ac97, HZ/2) < 0) {
+			snd_printk("MC'97 %d:%d does not respond - MODEM RESET\n", ac97->num, ac97->addr);
+			snd_ac97_free(ac97);
+			return -ENXIO;
+		}
+	}
+      __access_ok:
+	ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;
+	ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
+	if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) {
+		snd_printk("MC'97 %d:%d access is not valid [0x%x], removing modem controls.\n", ac97->num, ac97->addr, ac97->id);
+		snd_ac97_free(ac97);
+		return -EIO;
+	}
+	
+	/* test for MC'97 */
+	ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);
+	if (ac97->ext_mid == 0xffff)	/* invalid combination */
+		ac97->ext_mid = 0;
+	if (ac97->ext_mid & 1)
+		ac97->scaps |= AC97_SCAP_MODEM;
+
+	/* non-destructive test for AC'97 */
+	tmp = snd_ac97_read(ac97, AC97_RESET);
+	if (tmp == 0 || tmp == 0xffff) {
+		tmp = snd_ac97_read(ac97, AC97_EXTENDED_ID);
+		if (tmp == 0 || tmp == 0xffff) {
+			tmp = snd_ac97_read(ac97, AC97_REC_GAIN);
+			if (tmp == 0 || tmp == 0xffff)
+				tmp = snd_ac97_read(ac97, AC97_POWERDOWN);
+		}
+	}
+	if ((tmp != 0 && tmp != 0xffff) || !(ac97->scaps & AC97_SCAP_MODEM))
+		ac97->scaps |= AC97_SCAP_AUDIO;
+
+	if (ac97->reset) // FIXME: always skipping?
+		goto __ready_ok;
+
+	/* FIXME: add powerdown control */
 	if (ac97->scaps & AC97_SCAP_MODEM) {
+		/* nothing should be in powerdown mode */
+		/* note: it's important to set the rate at first */
+		tmp = AC97_MEA_GPIO;
+		if (ac97->ext_mid & AC97_MEI_LINE1) {
+			snd_ac97_write_cache_test(ac97, AC97_LINE1_RATE, 12000);
+			tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1;
+		}
+		if (ac97->ext_mid & AC97_MEI_LINE2) {
+			snd_ac97_write_cache_test(ac97, AC97_LINE2_RATE, 12000);
+			tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2;
+		}
+		if (ac97->ext_mid & AC97_MEI_HANDSET) {
+			snd_ac97_write_cache_test(ac97, AC97_HANDSET_RATE, 12000);
+			tmp |= AC97_MEA_HADC | AC97_MEA_HDAC;
+		}
+		snd_ac97_write_cache_test(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
+		udelay(100);
+		/* nothing should be in powerdown mode */
+		snd_ac97_write_cache_test(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
+		end_time = jiffies + (HZ / 10);
+		do {
+			if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp)
+				goto __ready_ok;
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ/10);
+		} while (time_after_eq(end_time, jiffies));
+		snd_printk("MC'97 %d:%d converters and GPIO not ready (0x%x)\n", ac97->num, ac97->addr, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
+	}
+
+      __ready_ok:
+	/* additional initializations */
+	/* FIXME: ADD MODEM INITALIZATION */
+	if (ac97_is_modem(ac97))
+		ac97->addr = (ac97->ext_mid & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT;
+	else
+		ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT;
+
+	if (ac97->init)
+		ac97->init(ac97);
+	snd_ac97_get_name(ac97, ac97->id, name, 1);
+	snd_ac97_get_name(NULL, ac97->id, name, 1);  // ac97->id might be changed in the special setup code
+	if (ac97_is_modem(ac97)) {
+		if (card->mixername[0] == '\0') {
+			strcpy(card->mixername, name);
+		} else {
+			if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {
+				strcat(card->mixername, ",");
+				strcat(card->mixername, name);
+			}
+		}
 		if ((err = snd_component_add(card, "AC97m")) < 0) {
 			snd_ac97_free(ac97);
 			return err;
 		}
 	}
-	if (snd_ac97_mixer_build(card, ac97) < 0) {
+	if (ac97_is_modem(ac97) && snd_ac97_modem_build(card, ac97) < 0) {
 		snd_ac97_free(ac97);
 		return -ENOMEM;
 	}
-	snd_ac97_proc_init(card, ac97);
+	snd_ac97_proc_init(card, ac97, "mc97");
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) {
 		snd_ac97_free(ac97);
 		return err;
@@ -2035,7 +2282,7 @@
 
 	id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;
 	id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
-	snd_ac97_get_name(NULL, id, name);
+	snd_ac97_get_name(NULL, id, name, 0);
 	snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name);
 	if ((ac97->scaps & AC97_SCAP_AUDIO) == 0)
 		goto __modem;
@@ -2165,9 +2412,39 @@
 			(mext & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT,
 			mext & AC97_MEI_CID2 ? " CID2" : "",
 			mext & AC97_MEI_CID1 ? " CID1" : "",
-			mext & AC97_MEI_HEADSET ? " HSET" : "",
+			mext & AC97_MEI_HANDSET ? " HSET" : "",
 			mext & AC97_MEI_LINE2 ? " LIN2" : "",
 			mext & AC97_MEI_LINE1 ? " LIN1" : "");
+	val = snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS);
+	snd_iprintf(buffer, "Modem status     :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+			val & AC97_MEA_GPIO ? " GPIO" : "",
+			val & AC97_MEA_MREF ? " MREF" : "",
+			val & AC97_MEA_ADC1 ? " ADC1" : "",
+			val & AC97_MEA_DAC1 ? " DAC1" : "",
+			val & AC97_MEA_ADC2 ? " ADC2" : "",
+			val & AC97_MEA_DAC2 ? " DAC2" : "",
+			val & AC97_MEA_HADC ? " HADC" : "",
+			val & AC97_MEA_HDAC ? " HDAC" : "",
+			val & AC97_MEA_PRA ? " PRA(GPIO)" : "",
+			val & AC97_MEA_PRB ? " PRB(res)" : "",
+			val & AC97_MEA_PRC ? " PRC(ADC1)" : "",
+			val & AC97_MEA_PRD ? " PRD(DAC1)" : "",
+			val & AC97_MEA_PRE ? " PRE(ADC2)" : "",
+			val & AC97_MEA_PRF ? " PRF(DAC2)" : "",
+			val & AC97_MEA_PRG ? " PRG(HADC)" : "",
+			val & AC97_MEA_PRH ? " PRH(HDAC)" : "");
+	if (mext & AC97_MEI_LINE1) {
+		val = snd_ac97_read(ac97, AC97_LINE1_RATE);
+		snd_iprintf(buffer, "Line1 rate       : %iHz\n", val);
+	}
+	if (mext & AC97_MEI_LINE2) {
+		val = snd_ac97_read(ac97, AC97_LINE2_RATE);
+		snd_iprintf(buffer, "Line2 rate       : %iHz\n", val);
+	}
+	if (mext & AC97_MEI_HANDSET) {
+		val = snd_ac97_read(ac97, AC97_HANDSET_RATE);
+		snd_iprintf(buffer, "Headset rate     : %iHz\n", val);
+	}
 }
 
 static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
@@ -2235,21 +2512,21 @@
 	}	
 }
 
-static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97)
+static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix)
 {
 	snd_info_entry_t *entry;
 	char name[32];
 
 	if (ac97->num)
-		sprintf(name, "ac97#%d-%d", ac97->addr, ac97->num);
+		sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num);
 	else
-		sprintf(name, "ac97#%d", ac97->addr);
+		sprintf(name, "%s#%d", prefix, ac97->addr);
 	if (! snd_card_proc_new(card, name, &entry))
 		snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read);
 	if (ac97->num)
-		sprintf(name, "ac97#%d-%dregs", ac97->addr, ac97->num);
+		sprintf(name, "%s#%d-%dregs", prefix, ac97->addr, ac97->num);
 	else
-		sprintf(name, "ac97#%dregs", ac97->addr);
+		sprintf(name, "%s#%dregs", prefix, ac97->addr);
 	if (! snd_card_proc_new(card, name, &entry))
 		snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read);
 }
@@ -2430,6 +2707,7 @@
 	snd_ctl_elem_id_t id;
 	memset(&id, 0, sizeof(id));
 	strcpy(id.name, name);
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	return snd_ctl_remove_id(ac97->card, &id);
 }
 
@@ -2438,8 +2716,10 @@
 	snd_ctl_elem_id_t sid, did;
 	memset(&sid, 0, sizeof(sid));
 	strcpy(sid.name, src);
+	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	memset(&did, 0, sizeof(did));
 	strcpy(did.name, dst);
+	did.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	return snd_ctl_rename_id(ac97->card, &sid, &did);
 }
 
@@ -2476,19 +2756,21 @@
 {
 	unsigned short vendor, device;
 
+	snd_assert(quirk, return -EINVAL);
+
 	pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &vendor);
 	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &device);
 
 	for (; quirk->vendor; quirk++) {
 		if (quirk->vendor == vendor && quirk->device == device) {
-			snd_printdd("ac97 quirk for %04x:%04x\n", vendor, device);
+			snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, vendor, device);
 			switch (quirk->type) {
 			case AC97_TUNE_HP_ONLY:
 				return swap_headphone(ac97, 1);
 			case AC97_TUNE_SWAP_HP:
 				return swap_headphone(ac97, 0);
 			}
-			snd_printk(KERN_ERR "invalid quirk type %d\n", quirk->type);
+			snd_printk(KERN_ERR "invalid quirk type %d for %s\n", quirk->type, quirk->name);
 			return -EINVAL;
 		}
 	}
@@ -2506,6 +2788,7 @@
 EXPORT_SYMBOL(snd_ac97_update);
 EXPORT_SYMBOL(snd_ac97_update_bits);
 EXPORT_SYMBOL(snd_ac97_mixer);
+EXPORT_SYMBOL(snd_ac97_modem);
 EXPORT_SYMBOL(snd_ac97_set_rate);
 EXPORT_SYMBOL(snd_ac97_tune_hardware);
 #ifdef CONFIG_PM
diff -urN linux-2.5.65-bk1/sound/pci/ac97/ac97_id.h linux-2.5.65-bk2/sound/pci/ac97/ac97_id.h
--- linux-2.5.65-bk1/sound/pci/ac97/ac97_id.h	Mon Mar 17 13:44:47 2003
+++ linux-2.5.65-bk2/sound/pci/ac97/ac97_id.h	Mon Mar 31 12:39:51 2003
@@ -31,6 +31,7 @@
 #define AC97_ID_AD1886		0x41445361
 #define AC97_ID_AD1887		0x41445362
 #define AC97_ID_AD1886A		0x41445363
+#define AC97_ID_AD1980 		0x41445370
 #define AC97_ID_TR28028		0x54524108
 #define AC97_ID_STAC9700	0x83847600
 #define AC97_ID_STAC9704	0x83847604
diff -urN linux-2.5.65-bk1/sound/pci/ac97/ac97_patch.c linux-2.5.65-bk2/sound/pci/ac97/ac97_patch.c
--- linux-2.5.65-bk1/sound/pci/ac97/ac97_patch.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/sound/pci/ac97/ac97_patch.c	Mon Mar 31 12:39:51 2003
@@ -366,7 +366,7 @@
 
 	val = snd_ac97_read(ac97, AC97_ALC650_MULTICH);
 	val &= ~0xc000; /* slot: 3,4,7,8,6,9 */
-	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val | 0x03);
+	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val);
 
 	/* full DAC volume */
 	snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
diff -urN linux-2.5.65-bk1/sound/pci/cs46xx/cs46xx_lib.c linux-2.5.65-bk2/sound/pci/cs46xx/cs46xx_lib.c
--- linux-2.5.65-bk1/sound/pci/cs46xx/cs46xx_lib.c	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/sound/pci/cs46xx/cs46xx_lib.c	Mon Mar 31 12:39:51 2003
@@ -321,6 +321,7 @@
 #include "imgs/cwcasync.h"
 #include "imgs/cwcsnoop.h"
 #include "imgs/cwcbinhack.h"
+#include "imgs/cwcdma.h"
 
 int snd_cs46xx_clear_BA1(cs46xx_t *chip,
                          unsigned long offset,
@@ -672,28 +673,21 @@
  *  PCM part
  */
 
-static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream, 
-					snd_pcm_uframes_t frames)
+static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream)
 {
 	/* cs46xx_t *chip = snd_pcm_substream_chip(substream); */
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
 	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
-	snd_pcm_sframes_t diff;
-	cs46xx_pcm_t * cpcm;
-	int buffer_size;
-
-	cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
-
-	buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift;
+	snd_pcm_sframes_t diff = appl_ptr - cpcm->appl_ptr;
+	int buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift;
 
-	diff = appl_ptr - cpcm->appl_ptr;
 	if (diff) {
 		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 			diff += runtime->boundary;
-		frames += diff;
+		cpcm->sw_ready += diff * (1 << cpcm->shift);
+		cpcm->appl_ptr = appl_ptr;
 	}
-	cpcm->sw_ready += frames << cpcm->shift;
-	cpcm->appl_ptr = appl_ptr + frames;
 	while (cpcm->hw_ready < buffer_size && 
 	       cpcm->sw_ready > 0) {
 		size_t hw_to_end = buffer_size - cpcm->hw_data;
@@ -720,21 +714,20 @@
 	return 0;
 }
 
-static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream, 
-				       snd_pcm_uframes_t frames)
+static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
 	snd_pcm_sframes_t diff = appl_ptr - chip->capt.appl_ptr;
 	int buffer_size = runtime->period_size * CS46XX_FRAGS << chip->capt.shift;
+
 	if (diff) {
 		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 			diff += runtime->boundary;
-		frames += diff;
+		chip->capt.sw_ready -= diff * (1 << chip->capt.shift);
+		chip->capt.appl_ptr = appl_ptr;
 	}
-	chip->capt.sw_ready -= frames << chip->capt.shift;
-	chip->capt.appl_ptr = appl_ptr + frames;
 	while (chip->capt.hw_ready > 0 && 
 	       chip->capt.sw_ready < (int)chip->capt.sw_bufsize) {
 		size_t hw_to_end = buffer_size - chip->capt.hw_data;
@@ -802,7 +795,7 @@
 	cpcm->sw_io += bytes;
 	if (cpcm->sw_io >= cpcm->sw_bufsize)
 		cpcm->sw_io -= cpcm->sw_bufsize;
-	snd_cs46xx_playback_transfer(substream, 0);
+	snd_cs46xx_playback_transfer(substream);
 	return cpcm->sw_io >> cpcm->shift;
 }
 
@@ -827,57 +820,10 @@
 	chip->capt.sw_io += bytes;
 	if (chip->capt.sw_io >= chip->capt.sw_bufsize)
 		chip->capt.sw_io -= chip->capt.sw_bufsize;
-	snd_cs46xx_capture_transfer(substream, 0);
+	snd_cs46xx_capture_transfer(substream);
 	return chip->capt.sw_io >> chip->capt.shift;
 }
 
-static int snd_cs46xx_playback_copy(snd_pcm_substream_t *substream,
-				    int channel,
-				    snd_pcm_uframes_t hwoff,
-				    void *src,
-				    snd_pcm_uframes_t frames)
-{
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	/*cs46xx_t *chip = snd_pcm_substream_chip(substream); */
-	size_t hwoffb;
-	size_t bytes;
-	char *hwbuf;
-	cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
-
-	snd_assert(runtime->dma_area, return -EINVAL);
-
-	hwoffb = hwoff << cpcm->shift;
-	bytes = frames << cpcm->shift;
-	hwbuf = runtime->dma_area + hwoffb;
-
-	if (copy_from_user(hwbuf, src, bytes))
-		return -EFAULT;
-
-	spin_lock_irq(&runtime->lock);
-	snd_cs46xx_playback_transfer(substream, frames);
-	spin_unlock_irq(&runtime->lock);
-	return 0;
-}
-	
-static int snd_cs46xx_capture_copy(snd_pcm_substream_t *substream,
-				   int channel,
-				   snd_pcm_uframes_t hwoff,
-				   void *dst,
-				   snd_pcm_uframes_t frames)
-{
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	cs46xx_t *chip = snd_pcm_substream_chip(substream);
-	size_t hwoffb = hwoff << chip->capt.shift;
-	size_t bytes = frames << chip->capt.shift;
-	char *hwbuf = runtime->dma_area + hwoffb;
-	if (copy_to_user(dst, hwbuf, bytes))
-		return -EFAULT;
-	spin_lock_irq(&runtime->lock);
-	snd_cs46xx_capture_transfer(substream, frames);
-	spin_unlock_irq(&runtime->lock);
-	return 0;
-}
-	
 static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
 				       int cmd)
 {
@@ -909,10 +855,10 @@
 			cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
 
 		if (substream->runtime->periods != CS46XX_FRAGS)
-			snd_cs46xx_playback_transfer(substream, 0);
+			snd_cs46xx_playback_transfer(substream);
 #else
 		if (substream->runtime->periods != CS46XX_FRAGS)
-			snd_cs46xx_playback_transfer(substream, 0);
+			snd_cs46xx_playback_transfer(substream);
 		{ unsigned int tmp;
 		tmp = snd_cs46xx_peek(chip, BA1_PCTL);
 		tmp &= 0x0000ffff;
@@ -1018,13 +964,14 @@
 static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
 					 snd_pcm_hw_params_t * hw_params)
 {
-	/*cs46xx_t *chip = snd_pcm_substream_chip(substream);*/
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	cs46xx_pcm_t *cpcm;
 	int err;
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	int sample_rate = params_rate(hw_params);
 	int period_size = params_period_bytes(hw_params);
+#endif
 	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
@@ -1211,10 +1158,9 @@
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	int err;
-	int period_size = params_period_bytes(hw_params);
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	cs46xx_dsp_pcm_ostream_set_period (chip,period_size);
+	cs46xx_dsp_pcm_ostream_set_period (chip, params_period_bytes(hw_params));
 #endif
 	if (runtime->periods == CS46XX_FRAGS) {
 		if (runtime->dma_area != chip->capt.hw_area)
@@ -1399,6 +1345,8 @@
 	.fifo_size =		0,
 };
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+
 static unsigned int period_sizes[] = { 32, 64, 128, 256, 512, 1024, 2048 };
 
 #define PERIOD_SIZES sizeof(period_sizes) / sizeof(period_sizes[0])
@@ -1409,6 +1357,8 @@
 	.mask = 0
 };
 
+#endif
+
 static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime)
 {
 	cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return);
@@ -1587,8 +1537,8 @@
 	.hw_free =		snd_cs46xx_playback_hw_free,
 	.prepare =		snd_cs46xx_playback_prepare,
 	.trigger =		snd_cs46xx_playback_trigger,
-	.copy =			snd_cs46xx_playback_copy,
 	.pointer =		snd_cs46xx_playback_indirect_pointer,
+	.ack =			snd_cs46xx_playback_transfer,
 };
 
 snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = {
@@ -1610,8 +1560,8 @@
 	.hw_free =		snd_cs46xx_playback_hw_free,
 	.prepare =		snd_cs46xx_playback_prepare,
 	.trigger =		snd_cs46xx_playback_trigger,
-	.copy =			snd_cs46xx_playback_copy,
 	.pointer =		snd_cs46xx_playback_indirect_pointer,
+	.ack =			snd_cs46xx_playback_transfer,
 };
 
 #endif
@@ -1635,8 +1585,8 @@
 	.hw_free =		snd_cs46xx_playback_hw_free,
 	.prepare =		snd_cs46xx_playback_prepare,
 	.trigger =		snd_cs46xx_playback_trigger,
-	.copy =			snd_cs46xx_playback_copy,
 	.pointer =		snd_cs46xx_playback_indirect_pointer,
+	.ack =			snd_cs46xx_playback_transfer,
 };
 
 snd_pcm_ops_t snd_cs46xx_capture_ops = {
@@ -1658,8 +1608,8 @@
 	.hw_free =		snd_cs46xx_capture_hw_free,
 	.prepare =		snd_cs46xx_capture_prepare,
 	.trigger =		snd_cs46xx_capture_trigger,
-	.copy =			snd_cs46xx_capture_copy,
 	.pointer =		snd_cs46xx_capture_indirect_pointer,
+	.ack =			snd_cs46xx_capture_transfer,
 };
 
 static void snd_cs46xx_pcm_free(snd_pcm_t *pcm)
@@ -1941,7 +1891,8 @@
 		res = (change != chip->dsp_spos_instance->spdif_status_in);
 		break;
 	default:
-		snd_assert(0, return -EINVAL);
+		res = -EINVAL;
+		snd_assert(0, (void)0);
 	}
 
 	return res;
@@ -2365,7 +2316,7 @@
 
 static void snd_cs46xx_sec_codec_reset (ac97_t * ac97)
 {
-	signed long end_time;
+	unsigned long end_time;
 	int err;
 
 	/* reset to defaults */
@@ -2401,7 +2352,7 @@
 		schedule_timeout(HZ/100);
 	} while (time_after_eq(end_time, jiffies));
 
-	snd_printk("CS46xx secondary codec don't respond!\n");  
+	snd_printk("CS46xx secondary codec dont respond!\n");  
 }
 #endif
 
@@ -2505,9 +2456,6 @@
 	strcpy(id.name, "External Amplifier Power Down");
 	chip->eapd_switch = snd_ctl_find_id(chip->card, &id);
     
-	/* turn on amplifier */
-	chip->amplifier_ctrl(chip, 1);
-
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	/* do soundcard specific mixer setup */
 	if (chip->mixer_init) {
@@ -2515,6 +2463,9 @@
 		chip->mixer_init(chip);
 	}
 #endif
+
+ 	/* turn on amplifier */
+	chip->amplifier_ctrl(chip, 1);
     
 	return 0;
 }
@@ -2919,10 +2870,6 @@
 		kfree(chip->gameport);
 	}
 #endif
-#ifdef CONFIG_PM
-	if (chip->pm_dev)
-		pm_unregister(chip->pm_dev);
-#endif
 	if (chip->amplifier_ctrl)
 		chip->amplifier_ctrl(chip, -chip->amplifier); /* force to off */
 	
@@ -3227,6 +3174,11 @@
 		return -EIO;
 	}
 
+	if (cs46xx_dsp_load_module(chip, &cwcdma_module) < 0) {
+		snd_printk(KERN_ERR "image download error [cwcdma]\n");
+		return -EIO;
+	}
+
 	if (cs46xx_dsp_scb_and_task_init(chip) < 0)
 		return -EIO;
 #else
@@ -3436,10 +3388,10 @@
 	oval = snd_cs46xx_codec_read(chip, AC97_POWERDOWN,
 				     CS46XX_PRIMARY_CODEC_INDEX);
 	val = oval;
-	if (chip->amplifier && !old) {
+	if (chip->amplifier) {
 		/* Turn the EAPD amp on */
 		val |= 0x8000;
-	} else if (old && !chip->amplifier) {
+	} else {
 		/* Turn the EAPD amp off */
 		val &= ~0x8000;
 	}
@@ -3574,23 +3526,23 @@
  
 static void clkrun_hack(cs46xx_t *chip, int change)
 {
-	u16 control;
-	int old;
+	u16 control, nval;
 	
 	if (chip->acpi_dev == NULL)
 		return;
 
-	old = chip->amplifier;
 	chip->amplifier += change;
 	
 	/* Read ACPI port */	
-	control = inw(chip->acpi_port + 0x10);
+	nval = control = inw(chip->acpi_port + 0x10);
 
 	/* Flip CLKRUN off while running */
-	if (! chip->amplifier && old)
-		outw(control | 0x2000, chip->acpi_port + 0x10);
-	else if (chip->amplifier && ! old)
-		outw(control & ~0x2000, chip->acpi_port + 0x10);
+	if (! chip->amplifier)
+		nval |= 0x2000;
+	else
+		nval &= ~0x2000;
+	if (nval != control)
+		outw(nval, chip->acpi_port + 0x10);
 }
 
 	
diff -urN linux-2.5.65-bk1/sound/pci/cs46xx/cs46xx_lib.h linux-2.5.65-bk2/sound/pci/cs46xx/cs46xx_lib.h
--- linux-2.5.65-bk1/sound/pci/cs46xx/cs46xx_lib.h	Mon Mar 17 13:43:43 2003
+++ linux-2.5.65-bk2/sound/pci/cs46xx/cs46xx_lib.h	Mon Mar 31 12:39:51 2003
@@ -156,7 +156,8 @@
                                                        u16 src_buffer_addr,
                                                        u16 src_delay_buffer_addr,u32 dest,
                                                        dsp_scb_descriptor_t * parent_scb,
-                                                       int scb_child_type);
+                                                       int scb_child_type,
+						       int pass_through);
 dsp_scb_descriptor_t *  cs46xx_dsp_create_mix_only_scb(cs46xx_t * chip,char * scb_name,
                                                        u16 mix_buffer_addr,u32 dest,
                                                        dsp_scb_descriptor_t * parent_scb,
diff -urN linux-2.5.65-bk1/sound/pci/cs46xx/dsp_spos.c linux-2.5.65-bk2/sound/pci/cs46xx/dsp_spos.c
--- linux-2.5.65-bk1/sound/pci/cs46xx/dsp_spos.c	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/sound/pci/cs46xx/dsp_spos.c	Mon Mar 31 12:39:51 2003
@@ -1371,11 +1371,11 @@
 
 	/* SPDIF input sampel rate converter */
 	src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
-						      48000,
+						      ins->spdif_in_sample_rate,
 						      SRC_OUTPUT_BUF1,
 						      SRC_DELAY_BUF1,SRCTASK_SCB_ADDR,
 						      master_mix_scb,
-						      SCB_ON_PARENT_SUBLIST_SCB);
+						      SCB_ON_PARENT_SUBLIST_SCB,0);
 
 	if (!src_task_scb) goto _fail_end;
 
@@ -1564,10 +1564,33 @@
 	return 0;
 }
 
+
+static void cs46xx_dsp_disable_spdif_hw (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	/* set SPDIF output FIFO slot */
+	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0);
+
+	/* SPDIF output MASTER ENABLE */
+	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0);
+
+	/* right and left validate bit */
+	/*cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);*/
+	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x0);
+
+	/* monitor state */
+	ins->spdif_status_out &= ~DSP_SPDIF_STATUS_HW_ENABLED;
+}
+
 int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip)
 {
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
 
+	/* if hw-ctrl already enabled, turn off to reset logic ... */
+	cs46xx_dsp_disable_spdif_hw (chip);
+	udelay(50);
+
 	/* set SPDIF output FIFO slot */
 	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, ( 0x8000 | ((SP_SPDOUT_FIFO >> 4) << 4) ));
 
diff -urN linux-2.5.65-bk1/sound/pci/cs46xx/dsp_spos_scb_lib.c linux-2.5.65-bk2/sound/pci/cs46xx/dsp_spos_scb_lib.c
--- linux-2.5.65-bk1/sound/pci/cs46xx/dsp_spos_scb_lib.c	Mon Mar 17 13:44:44 2003
+++ linux-2.5.65-bk2/sound/pci/cs46xx/dsp_spos_scb_lib.c	Mon Mar 31 12:39:51 2003
@@ -584,7 +584,8 @@
                                u16 src_buffer_addr,
                                u16 src_delay_buffer_addr,u32 dest,
                                dsp_scb_descriptor_t * parent_scb,
-                               int scb_child_type)
+                               int scb_child_type,
+	                       int pass_through)
 {
 
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
@@ -659,10 +660,22 @@
 		/* clear buffers */
 		_dsp_clear_sample_buffer (chip,src_buffer_addr,8);
 		_dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
-		
-		scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
-					      dest,ins->s16_up,parent_scb,
-					      scb_child_type);
+				
+		if (pass_through) {
+			/* wont work with any other rate than
+			   the native DSP rate */
+			snd_assert (rate = 48000);
+
+			scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
+							    dest,"DMAREADER",parent_scb,
+							    scb_child_type);
+		} else {
+			scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
+						      dest,ins->s16_up,parent_scb,
+						      scb_child_type);
+		}
+
+
 	}
 
 	return scb;
@@ -835,10 +848,10 @@
 
 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
 		0,
-		0,input_scb->address,
+      /* 0xD */ 0,input_scb->address,
 		{
-			0x8000,0x8000,
-			0x8000,0x8000
+      /* 0xE */   0x8000,0x8000,
+      /* 0xF */	  0x8000,0x8000
 		}
 	};
 
@@ -1134,9 +1147,9 @@
 	dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb, * mixer_scb = NULL;
 	dsp_scb_descriptor_t * src_parent_scb = NULL;
 
-	/*dsp_scb_descriptor_t * pcm_parent_scb;*/
+	/* dsp_scb_descriptor_t * pcm_parent_scb; */
 	char scb_name[DSP_MAX_SCB_NAME];
-	int i,pcm_index = -1, insert_point, src_index = -1;
+	int i,pcm_index = -1, insert_point, src_index = -1,pass_through = 0;
 	unsigned long flags;
 
 	switch (pcm_channel_id) {
@@ -1163,7 +1176,8 @@
 		   alter the raw data stream ...) */
 		if (sample_rate == 48000) {
 			snd_printdd ("IEC958 pass through\n");
-			src_parent_scb = ins->asynch_tx_scb;
+			/* Hack to bypass creating a new SRC */
+			pass_through = 1;
 		}
 		break;
 	default:
@@ -1216,18 +1230,16 @@
 		snd_assert (src_index != -1,return NULL);
 
 		/* we need to create a new SRC SCB */
-		if (src_parent_scb == NULL) {
-			if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
-				src_parent_scb = mixer_scb;
-				insert_point = SCB_ON_PARENT_SUBLIST_SCB;
-			} else {
-				src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
-				insert_point = SCB_ON_PARENT_NEXT_SCB;
-			}
-		} else insert_point = SCB_ON_PARENT_NEXT_SCB;
+		if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
+			src_parent_scb = mixer_scb;
+			insert_point = SCB_ON_PARENT_SUBLIST_SCB;
+		} else {
+			src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
+			insert_point = SCB_ON_PARENT_NEXT_SCB;
+		}
 
 		snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
-
+		
 		snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
 		src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
 							 sample_rate,
@@ -1236,7 +1248,8 @@
 							 /* 0x400 - 0x600 source SCBs */
 							 0x400 + (src_index * 0x10) ,
 							 src_parent_scb,
-							 insert_point);
+							 insert_point,
+							 pass_through);
 
 		if (!src_scb) {
 			snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
@@ -1268,19 +1281,6 @@
 		snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
 		return NULL;
 	}
-
-	if (pcm_channel_id == DSP_IEC958_CHANNEL && sample_rate == 48000) {
-		snd_assert (ins->spdif_pcm_input_scb == NULL);
-		
-		/* a hack to make the skip the SRC and pass the stream 
-		   directly to the SPDIF task */
-		ins->spdif_pcm_input_scb = 
-			cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_PCM",
-							       PCMSERIALINII_SCB_ADDR,
-							       pcm_scb,
-							       ins->asynch_tx_scb,
-							       SCB_ON_PARENT_SUBLIST_SCB);		
-	}
 	
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	ins->pcm_channels[pcm_index].sample_rate = sample_rate;
@@ -1540,7 +1540,7 @@
 		cs46xx_dsp_enable_spdif_hw (chip);
 	}
 
-	/* don't touch anything if SPDIF is open */
+	/* dont touch anything if SPDIF is open */
 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
 		/* when cs46xx_iec958_post_close(...) is called it
 		   will call this function if necessary depending on
@@ -1584,7 +1584,7 @@
 {
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
 
-	/* don't touch anything if SPDIF is open */
+	/* dont touch anything if SPDIF is open */
 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
 		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
 		return -EBUSY;
@@ -1625,7 +1625,7 @@
 	}
 	
 	/* if not enabled already */
-	if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
+	if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
 		cs46xx_dsp_enable_spdif_hw (chip);
 	}
 
@@ -1669,7 +1669,6 @@
 	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
 
 	/* restore state */
-
 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
 		cs46xx_dsp_enable_spdif_out (chip);
 	}
diff -urN linux-2.5.65-bk1/sound/pci/cs46xx/imgs/cwcdma.asp linux-2.5.65-bk2/sound/pci/cs46xx/imgs/cwcdma.asp
--- linux-2.5.65-bk1/sound/pci/cs46xx/imgs/cwcdma.asp	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/sound/pci/cs46xx/imgs/cwcdma.asp	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,169 @@
+// 
+//  Copyright(c) by Benny Sjostrand (benny@hostmobility.com)
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+
+
+//
+// This code runs inside the DSP (cs4610, cs4612, cs4624, or cs4630),
+// to compile it you need a tool named SPASM 3.0 and DSP code owned by 
+// Cirrus Logic(R). The SPASM program will generate a object file (cwcdma.osp),
+// the "ospparser"  tool will genereate the cwcdma.h file it's included from
+// the cs46xx_lib.c file.
+//
+//
+// The purpose of this code is very simple: make it possible to tranfser
+// the samples 'as they are' with no alteration from a PCMreader SCB (DMA from host)
+// to any other SCB. This is useful for AC3 throug SPDIF. SRC (source rate converters) 
+// task always alters the samples in some how, however it's from 48khz -> 48khz. The
+// alterations are not audible, but AC3 wont work. 
+//
+//        ...
+//         |
+// +---------------+
+// | AsynchFGTxSCB |
+// +---------------+
+//        |
+//    subListPtr
+//        |
+// +--------------+
+// |   DMAReader  |
+// +--------------+
+//        |
+//    subListPtr
+//        |
+// +-------------+
+// | PCMReader   |
+// +-------------+
+// (DMA from host)
+//
+
+struct dmaSCB
+  {
+    long  dma_reserved1[3];
+
+    short dma_reserved2:dma_outBufPtr;
+
+    short dma_unused1:dma_unused2;
+
+    long  dma_reserved3[4];
+
+    short dma_subListPtr:dma_nextSCB;
+    short dma_SPBptr:dma_entryPoint;
+
+    long  dma_strmRsConfig;
+    long  dma_strmBufPtr;
+
+    long  dma_reserved4;
+
+    VolumeControl s2m_volume;
+  };
+
+#export DMAReader
+void DMAReader()
+{
+  execChild();
+  r2 = r0->dma_subListPtr;
+  r1 = r0->nextSCB;
+	
+  rsConfig01 = r2->strmRsConfig;
+  // Load rsConfig for input buffer
+
+  rsDMA01 = r2->basicReq.daw,       ,                   tb = Z(0 - rf);
+  // Load rsDMA in case input buffer is a DMA buffer    Test to see if there is any data to transfer
+
+  if (tb) goto execSibling_2ind1 after {
+      r5 = rf + (-1);
+      r6 = r1->dma_entryPoint;           // r6 = entry point of sibling task
+      r1 = r1->dma_SPBptr,               // r1 = pointer to sibling task's SPB
+          ,   ind = r6;                  // Load entry point of sibling task
+  }
+
+  rsConfig23 = r0->dma_strmRsConfig;
+  // Load rsConfig for output buffer (never a DMA buffer)
+
+  r4 = r0->dma_outBufPtr;
+
+  rsa0 = r2->strmBufPtr;
+  // rsa0 = input buffer pointer                        
+
+  for (i = r5; i >= 0; --i)
+    after {
+      rsa2 = r4;
+      // rsa2 = output buffer pointer
+
+      nop;
+      nop;
+    }
+  //*****************************
+  // TODO: cycles to this point *
+  //*****************************
+    {
+      acc0 =  (rsd0 = *rsa0++1);
+      // get sample
+
+      nop;  // Those "nop"'s are really uggly, but there's
+      nop;  // something with DSP's pipelines which I don't
+      nop;  // understand, resulting this code to fail without
+            // having those "nop"'s (Benny)
+
+      rsa0?reqDMA = r2;
+      // Trigger DMA transfer on input stream, 
+      // if needed to replenish input buffer
+
+      nop;
+      // Yet another magic "nop" to make stuff work
+
+      ,,r98 = acc0 $+>> 0;
+      // store sample in ALU
+
+      nop;
+      // latency on load register.
+      // (this one is understandable)
+
+      *rsa2++1 = r98;
+      // store sample in output buffer
+
+      nop; // The same story
+      nop; // as above again ...
+      nop;
+    }
+  // TODO: cycles per loop iteration
+
+  r2->strmBufPtr = rsa0,,   ;
+  // Update the modified buffer pointers
+
+  r4 = rsa2;
+  // Load output pointer position into r4
+
+  r2 = r0->nextSCB;
+  // Sibling task
+
+  goto execSibling_2ind1 // takes 6 cycles
+    after {
+      r98 = r2->thisSPB:entryPoint;
+      // Load child routine entry and data address 
+
+      r1 = r9;
+      // r9 is r2->thisSPB
+
+      r0->dma_outBufPtr = r4,,
+      // Store updated output buffer pointer
+
+      ind = r8;
+      // r8 is r2->entryPoint
+    }
+}
diff -urN linux-2.5.65-bk1/sound/pci/cs46xx/imgs/cwcdma.h linux-2.5.65-bk2/sound/pci/cs46xx/imgs/cwcdma.h
--- linux-2.5.65-bk1/sound/pci/cs46xx/imgs/cwcdma.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/sound/pci/cs46xx/imgs/cwcdma.h	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,68 @@
+/* generated from cwcdma.osp DO NOT MODIFY */
+
+#ifndef __HEADER_cwcdma_H__
+#define __HEADER_cwcdma_H__
+
+symbol_entry_t cwcdma_symbols[] = {
+  { 0x8000, "EXECCHILD",0x03 },
+  { 0x8001, "EXECCHILD_98",0x03 },
+  { 0x8003, "EXECCHILD_PUSH1IND",0x03 },
+  { 0x8008, "EXECSIBLING",0x03 },
+  { 0x800a, "EXECSIBLING_298",0x03 },
+  { 0x800b, "EXECSIBLING_2IND1",0x03 },
+  { 0x8010, "TIMINGMASTER",0x03 },
+  { 0x804f, "S16_CODECINPUTTASK",0x03 },
+  { 0x805e, "PCMSERIALINPUTTASK",0x03 },
+  { 0x806d, "S16_MIX_TO_OSTREAM",0x03 },
+  { 0x809a, "S16_MIX",0x03 },
+  { 0x80bb, "S16_UPSRC",0x03 },
+  { 0x813b, "MIX3_EXP",0x03 },
+  { 0x8164, "DECIMATEBYPOW2",0x03 },
+  { 0x8197, "VARIDECIMATE",0x03 },
+  { 0x81f2, "_3DINPUTTASK",0x03 },
+  { 0x820a, "_3DPRLGCINPTASK",0x03 },
+  { 0x8227, "_3DSTEREOINPUTTASK",0x03 },
+  { 0x8242, "_3DOUTPUTTASK",0x03 },
+  { 0x82c4, "HRTF_MORPH_TASK",0x03 },
+  { 0x82c6, "WAIT4DATA",0x03 },
+  { 0x82fa, "PROLOGIC",0x03 },
+  { 0x8496, "DECORRELATOR",0x03 },
+  { 0x84a4, "STEREO2MONO",0x03 },
+  { 0x0000, "OVERLAYBEGINADDRESS",0x00 },
+  { 0x0000, "DMAREADER",0x03 },
+  { 0x0018, "#CODE_END",0x00 },
+}; /* cwcdma symbols */
+
+u32 cwcdma_code[] = {
+/* OVERLAYBEGINADDRESS */
+/* 0000 */ 0x00002731,0x00001400,0x0004c108,0x000e5044,
+/* 0002 */ 0x0005f608,0x00000000,0x000007ae,0x000be300,
+/* 0004 */ 0x00058630,0x00001400,0x0007afb0,0x000e9584,
+/* 0006 */ 0x00007301,0x000a9840,0x0005e708,0x000cd104,
+/* 0008 */ 0x00067008,0x00000000,0x000902a0,0x00001000,
+/* 000A */ 0x00012a01,0x000c0000,0x00000000,0x00000000,
+/* 000C */ 0x00021843,0x000c0000,0x00000000,0x000c0000,
+/* 000E */ 0x0000e101,0x000c0000,0x00000cac,0x00000000,
+/* 0010 */ 0x00080000,0x000e5ca1,0x00000000,0x000c0000,
+/* 0012 */ 0x00000000,0x00000000,0x00000000,0x00092c00,
+/* 0014 */ 0x000122c1,0x000e5084,0x00058730,0x00001400,
+/* 0016 */ 0x000d7488,0x000e4782,0x00007401,0x0001c100
+};
+
+/* #CODE_END */
+
+segment_desc_t cwcdma_segments[] = {
+  { SEGTYPE_SP_PROGRAM, 0x00000000, 0x00000030, cwcdma_code },
+};
+
+dsp_module_desc_t cwcdma_module = {
+  "cwcdma",
+  {
+    27,
+    cwcdma_symbols
+  },
+  1,
+  cwcdma_segments,
+};
+
+#endif /* __HEADER_cwcdma_H__ */
diff -urN linux-2.5.65-bk1/sound/pci/emu10k1/emu10k1_main.c linux-2.5.65-bk2/sound/pci/emu10k1/emu10k1_main.c
--- linux-2.5.65-bk1/sound/pci/emu10k1/emu10k1_main.c	Mon Mar 17 13:44:48 2003
+++ linux-2.5.65-bk2/sound/pci/emu10k1/emu10k1_main.c	Mon Mar 31 12:39:51 2003
@@ -222,12 +222,21 @@
 		outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
 
 	if (enable_ir) {	/* enable IR for SB Live */
-		unsigned int reg = inl(emu->port + HCFG);
-		outl(reg | HCFG_GPOUT2, emu->port + HCFG);
-		udelay(500);
-		outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG);
-		udelay(100);
-		outl(reg, emu->port + HCFG);
+		if (emu->audigy) {
+			unsigned int reg = inl(emu->port + A_IOCFG);
+			outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
+			udelay(500);
+			outl(reg | A_IOCFG_GPOUT1 | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
+			udelay(100);
+			outl(reg, emu->port + A_IOCFG);
+		} else {
+			unsigned int reg = inl(emu->port + HCFG);
+			outl(reg | HCFG_GPOUT2, emu->port + HCFG);
+			udelay(500);
+			outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG);
+			udelay(100);
+			outl(reg, emu->port + HCFG);
+ 		}
 	}
 	
 	if (!emu->APS) {	/* enable analog output */
@@ -581,22 +590,17 @@
 	/* enable PCI device */
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
-	/* set the DMA transfer mask */
-	if (is_audigy) {
-		if (pci_set_dma_mask(pci, 0xffffffff) < 0) {
-			snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
-			return -ENXIO;
-		}
-	} else {
-		if (pci_set_dma_mask(pci, 0x1fffffff) < 0) {
-			snd_printk(KERN_ERR "architecture does not support 29bit PCI busmaster DMA\n");
-			return -ENXIO;
-		}
-	}
 
 	emu = snd_magic_kcalloc(emu10k1_t, 0, GFP_KERNEL);
 	if (emu == NULL)
 		return -ENOMEM;
+	/* set the DMA transfer mask */
+	emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK;
+	if (pci_set_dma_mask(pci, emu->dma_mask) < 0) {
+		snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask);
+		snd_magic_kfree(emu);
+		return -ENXIO;
+	}
 	emu->card = card;
 	spin_lock_init(&emu->reg_lock);
 	spin_lock_init(&emu->emu_lock);
diff -urN linux-2.5.65-bk1/sound/pci/emu10k1/emufx.c linux-2.5.65-bk2/sound/pci/emu10k1/emufx.c
--- linux-2.5.65-bk1/sound/pci/emu10k1/emufx.c	Mon Mar 17 13:44:07 2003
+++ linux-2.5.65-bk2/sound/pci/emu10k1/emufx.c	Mon Mar 31 12:39:51 2003
@@ -520,8 +520,7 @@
 	*tram_pos -= frames;
 }
 
-static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream,
-						snd_pcm_uframes_t frames)
+static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream)
 {
 	emu10k1_t *emu = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
@@ -529,13 +528,13 @@
 	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
 	snd_pcm_sframes_t diff = appl_ptr - pcm->appl_ptr;
 	snd_pcm_uframes_t buffer_size = pcm->buffer_size / 2;
+
 	if (diff) {
 		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 			diff += runtime->boundary;
-		frames += diff;
+		pcm->sw_ready += diff;
+		pcm->appl_ptr = appl_ptr;
 	}
-	pcm->sw_ready += frames;
-	pcm->appl_ptr = appl_ptr + frames;
 	while (pcm->hw_ready < buffer_size &&
 	       pcm->sw_ready > 0) {
 	       	size_t hw_to_end = buffer_size - pcm->hw_data;
@@ -632,7 +631,7 @@
 		result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq);
 		if (result < 0)
 			goto __err;
-		snd_emu10k1_fx8010_playback_transfer(substream, 0);	/* roll the ball */
+		snd_emu10k1_fx8010_playback_transfer(substream);	/* roll the ball */
 		snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
@@ -670,28 +669,10 @@
 	pcm->sw_io += frames;
 	if (pcm->sw_io > runtime->buffer_size)
 		pcm->sw_io -= runtime->buffer_size;
-	snd_emu10k1_fx8010_playback_transfer(substream, 0);
+	snd_emu10k1_fx8010_playback_transfer(substream);
 	return pcm->sw_io;
 }
 
-static int snd_emu10k1_fx8010_playback_copy(snd_pcm_substream_t *substream,
-					    int channel,
-					    snd_pcm_uframes_t hwoff,
-					    void *src,
-					    snd_pcm_uframes_t frames)
-{
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	size_t hwoffb = hwoff << 2;
-	size_t bytes = frames << 2;
-	char *hwbuf = runtime->dma_area + hwoffb;
-	if (copy_from_user(hwbuf, src, bytes))
-		return -EFAULT;
-	spin_lock_irq(&runtime->lock);
-	snd_emu10k1_fx8010_playback_transfer(substream, frames);
-	spin_unlock_irq(&runtime->lock);
-	return 0;
-}
-
 static snd_pcm_hardware_t snd_emu10k1_fx8010_playback =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
@@ -748,8 +729,8 @@
 	.hw_free =		snd_emu10k1_fx8010_playback_hw_free,
 	.prepare =		snd_emu10k1_fx8010_playback_prepare,
 	.trigger =		snd_emu10k1_fx8010_playback_trigger,
-	.copy =			snd_emu10k1_fx8010_playback_copy,
 	.pointer =		snd_emu10k1_fx8010_playback_pointer,
+	.ack =			snd_emu10k1_fx8010_playback_transfer,
 };
 
 static void snd_emu10k1_fx8010_pcm_free(snd_pcm_t *pcm)
@@ -1221,7 +1202,7 @@
 	ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
 	ctl->min = 0;
 	ctl->max = 100;
-	ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;	
+	ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
 }
 
 static void __devinit snd_emu10k1_init_mono_onoff_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval)
@@ -1252,12 +1233,14 @@
  * initial DSP configuration for Audigy
  */
 
+#define A_GPR_ACCU 0xd6
+
 static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
 {
-	int err, i, gpr, tmp, playback, capture, nctl;
+	int err, i, z, gpr, tmp, playback, capture, nctl;
 	u32 ptr;
 	emu10k1_fx8010_code_t *icode;
-	emu10k1_fx8010_control_gpr_t *controls;
+	emu10k1_fx8010_control_gpr_t *controls, *ctl;
 	mm_segment_t seg;
 
 	spin_lock_init(&emu->fx8010.irq_lock);
@@ -1269,7 +1252,7 @@
 		kfree(icode);
 		return -ENOMEM;
 	}
-	
+
 	/* clear free GPRs */
 	for (i = 0; i < 256; i++)
 		set_bit(i, icode->gpr_valid);
@@ -1278,10 +1261,10 @@
 	ptr = 0;
 	nctl = 0;
 	playback = 10;
-	capture = playback + 10; /* we reserve 10 voices */
+	capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
 	gpr = capture + 10;
-	tmp = 0x80;
-	
+	tmp = 0x88;
+
 	/* stop FX processor */
 	snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
 
@@ -1422,21 +1405,111 @@
 #define A_PUT_STEREO_OUTPUT(out1,out2,src) \
 	{A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
 
+#define _A_SWITCH(icode, ptr, dst, src, sw) \
+	A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
+#define A_SWITCH(icode, ptr, dst, src, sw) \
+		_A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
+#define _A_SWITCH_NEG(icode, ptr, dst, src) \
+	A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
+#define A_SWITCH_NEG(icode, ptr, dst, src) \
+		_A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
+
+
+	/*
+	 *  Process tone control
+	 */
+	A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
+	A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
+	A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), A_GPR(playback + 2), A_C_00000000, A_C_00000000); /* rear left */
+	A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */
+	A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
+	A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */
+
+	ctl = &controls[nctl + 0];
+	ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strcpy(ctl->id.name, "Tone Control - Bass");
+	ctl->vcount = 2;
+	ctl->count = 10;
+	ctl->min = 0;
+	ctl->max = 40;
+	ctl->value[0] = ctl->value[1] = 20;
+	ctl->translation = EMU10K1_GRP_TRANSLATION_BASS;
+	ctl = &controls[nctl + 1];
+	ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strcpy(ctl->id.name, "Tone Control - Treble");
+	ctl->vcount = 2;
+	ctl->count = 10;
+	ctl->min = 0;
+	ctl->max = 40;
+	ctl->value[0] = ctl->value[1] = 20;
+	ctl->translation = EMU10K1_GRP_TRANSLATION_TREBLE;
+
+#define BASS_GPR	0x8c
+#define TREBLE_GPR	0x96
+
+	for (z = 0; z < 5; z++) {
+		int j;
+		for (j = 0; j < 2; j++) {
+			controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
+			controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
+		}
+	}
+	for (z = 0; z < 3; z++) {		/* front/rear/center-lfe */
+		int j, k, l, d;
+		for (j = 0; j < 2; j++) {	/* left/right */
+			k = 0xb0 + (z * 8) + (j * 4);
+			l = 0xe0 + (z * 8) + (j * 4);
+			d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
+
+			A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
+			A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
+			A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
+			A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
+			A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
+			A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
+
+			A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
+			A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
+			A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
+			A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
+			A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
+			A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
+
+			A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
+
+			if (z == 2)	/* center */
+				break;
+		}
+	}
+	nctl += 2;
+
+#undef BASS_GPR
+#undef TREBLE_GPR
+
+	for (z = 0; z < 6; z++) {
+		A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
+		A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
+		A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
+		A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
+	}
+	snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
+	gpr += 2;
+
 	/* digital outputs */
-	A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback);
-	A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2);
-	A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4);
-	A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5);
+	A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
+	A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
+	A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
+	A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
 
 	/* analog speakers */
-	//A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback);
-	A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback);
-	A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2);
-	A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4);
-	A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5);
+	//A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
+	A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
+	A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
+	A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
+	A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
 
 	/* headphone */
-	A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback);
+	A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
 
 	/* ADC buffer */
 	A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
@@ -1561,7 +1634,7 @@
 	gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
 	tmp = 0x88;	/* we need 4 temporary GPR */
 	/* from 0x8c to 0xff is the area for tone control */
-	
+
 	/* stop FX processor */
 	snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
 
@@ -1608,7 +1681,7 @@
 	icode->gpr_map[gpr + 12] = 0;
 
 	/* if the trigger flag is not set, skip */
-	/* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000); 
+	/* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
 	/* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
 	/* if the running flag is set, we're running */
 	/* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
diff -urN linux-2.5.65-bk1/sound/pci/emu10k1/emupcm.c linux-2.5.65-bk2/sound/pci/emu10k1/emupcm.c
--- linux-2.5.65-bk1/sound/pci/emu10k1/emupcm.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/sound/pci/emu10k1/emupcm.c	Mon Mar 31 12:39:51 2003
@@ -32,7 +32,6 @@
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
-#include <sound/pcm_sgbuf.h>
 
 #define chip_t emu10k1_t
 
diff -urN linux-2.5.65-bk1/sound/pci/emu10k1/emuproc.c linux-2.5.65-bk2/sound/pci/emu10k1/emuproc.c
--- linux-2.5.65-bk1/sound/pci/emu10k1/emuproc.c	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/sound/pci/emu10k1/emuproc.c	Mon Mar 31 12:39:51 2003
@@ -232,7 +232,7 @@
 }
 
 static struct snd_info_entry_ops snd_emu10k1_proc_ops_fx8010 = {
-	read: snd_emu10k1_fx8010_read,
+	.read = snd_emu10k1_fx8010_read,
 };
 
 int __devinit snd_emu10k1_proc_init(emu10k1_t * emu)
diff -urN linux-2.5.65-bk1/sound/pci/emu10k1/memory.c linux-2.5.65-bk2/sound/pci/emu10k1/memory.c
--- linux-2.5.65-bk1/sound/pci/emu10k1/memory.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/sound/pci/emu10k1/memory.c	Mon Mar 31 12:39:51 2003
@@ -25,7 +25,6 @@
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
-#include <sound/pcm_sgbuf.h>
 
 /* page arguments of these two macros are Emu page (4096 bytes), not like
  * aligned pages in others
@@ -229,10 +228,10 @@
 /*
  * check if the given pointer is valid for pages
  */
-static int is_valid_page(dma_addr_t addr)
+static int is_valid_page(emu10k1_t *emu, dma_addr_t addr)
 {
-	if (addr & ~0x7fffffffUL) {
-		snd_printk("max memory size is 2GB (addr = 0x%lx)!!\n", (unsigned long)addr);
+	if (addr & ~emu->dma_mask) {
+		snd_printk("max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr);
 		return 0;
 	}
 	if (addr & (EMUPAGESIZE-1)) {
@@ -291,18 +290,20 @@
 snd_util_memblk_t *
 snd_emu10k1_alloc_pages(emu10k1_t *emu, snd_pcm_substream_t *substream)
 {
-	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, _snd_pcm_substream_sgbuf(substream), return NULL);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_sg_buf *sgbuf = runtime->dma_private;
 	snd_util_memhdr_t *hdr;
 	emu10k1_memblk_t *blk;
 	int page, err, idx;
 
 	snd_assert(emu, return NULL);
-	snd_assert(sgbuf->size > 0 && sgbuf->size < MAXPAGES * EMUPAGESIZE, return NULL);
+	snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG, return NULL);
+	snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes < MAXPAGES * EMUPAGESIZE, return NULL);
 	hdr = emu->memhdr;
 	snd_assert(hdr, return NULL);
 
 	down(&hdr->block_mutex);
-	blk = search_empty(emu, sgbuf->size);
+	blk = search_empty(emu, runtime->dma_bytes);
 	if (blk == NULL) {
 		up(&hdr->block_mutex);
 		return NULL;
@@ -322,7 +323,7 @@
 		}
 #endif
 		addr = sgbuf->table[idx].addr;
-		if (! is_valid_page(addr)) {
+		if (! is_valid_page(emu, addr)) {
 			printk(KERN_ERR "emu: failure page = %d\n", idx);
 			up(&hdr->block_mutex);
 			return NULL;
@@ -445,7 +446,7 @@
 		ptr = snd_malloc_pci_page(emu->pci, &addr);
 		if (ptr == NULL)
 			goto __fail;
-		if (! is_valid_page(addr)) {
+		if (! is_valid_page(emu, addr)) {
 			snd_free_pci_page(emu->pci, ptr, addr);
 			goto __fail;
 		}
diff -urN linux-2.5.65-bk1/sound/pci/es1968.c linux-2.5.65-bk2/sound/pci/es1968.c
--- linux-2.5.65-bk1/sound/pci/es1968.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/sound/pci/es1968.c	Mon Mar 31 12:39:51 2003
@@ -555,9 +555,8 @@
 	unsigned int clock;		/* clock */
 
 	/* buffer */
-	void *dma_buf;
-	dma_addr_t dma_buf_addr;
-	unsigned long dma_buf_size;
+	struct snd_dma_device dma_dev;
+	struct snd_dma_buffer dma;
 
 	/* Resources... */
 	int irq;
@@ -1076,7 +1075,7 @@
 
 		/* Offset to PCMBAR */
 		pa = es->memory->addr;
-		pa -= chip->dma_buf_addr;
+		pa -= chip->dma.addr;
 		pa >>= 1;	/* words */
 
 		pa |= 0x00400000;	/* System RAM (Bit 22) */
@@ -1222,7 +1221,7 @@
 		snd_es1968_program_wavecache(chip, es, channel, pa, 1);
 
 		/* Offset to PCMBAR */
-		pa -= chip->dma_buf_addr;
+		pa -= chip->dma.addr;
 		pa >>= 1;	/* words */
 
 		/* base offset of dma calcs when reading the pointer
@@ -1499,9 +1498,9 @@
 {
 	struct list_head *p;
 
-	if (! chip->dma_buf)
+	if (! chip->dma.area)
 		return;
-	snd_free_pci_pages(chip->pci, chip->dma_buf_size, chip->dma_buf, chip->dma_buf_addr);
+	snd_dma_free_reserved(&chip->dma_dev);
 	while ((p = chip->buf_list.next) != &chip->buf_list) {
 		esm_memory_t *chunk = list_entry(p, esm_memory_t, list);
 		list_del(p);
@@ -1513,18 +1512,22 @@
 snd_es1968_init_dmabuf(es1968_t *chip)
 {
 	esm_memory_t *chunk;
-	chip->dma_buf = snd_malloc_pci_pages_fallback(chip->pci, chip->total_bufsize,
-						      &chip->dma_buf_addr, &chip->dma_buf_size);
-	//snd_printd("es1968: allocated buffer size %ld at %p\n", chip->dma_buf_size, chip->dma_buf);
-	if (chip->dma_buf == NULL) {
-		snd_printk("es1968: can't allocate dma pages for size %d\n",
-			   chip->total_bufsize);
-		return -ENOMEM;
-	}
-	if ((chip->dma_buf_addr + chip->dma_buf_size - 1) & ~((1 << 28) - 1)) {
-		snd_es1968_free_dmabuf(chip);
-		snd_printk("es1968: DMA buffer beyond 256MB.\n");
-		return -ENOMEM;
+
+	snd_dma_device_pci(&chip->dma_dev, chip->pci, 0);
+	if (! snd_dma_get_reserved(&chip->dma_dev, &chip->dma)) {
+		chip->dma.area = snd_malloc_pci_pages_fallback(chip->pci, chip->total_bufsize,
+							       &chip->dma.addr, &chip->dma.bytes);
+		if (chip->dma.area == NULL) {
+			snd_printk("es1968: can't allocate dma pages for size %d\n",
+				   chip->total_bufsize);
+			return -ENOMEM;
+		}
+		if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) {
+			snd_dma_free_pages(&chip->dma_dev, &chip->dma);
+			snd_printk("es1968: DMA buffer beyond 256MB.\n");
+			return -ENOMEM;
+		}
+		snd_dma_set_reserved(&chip->dma_dev, &chip->dma);
 	}
 
 	INIT_LIST_HEAD(&chip->buf_list);
@@ -1534,10 +1537,10 @@
 		snd_es1968_free_dmabuf(chip);
 		return -ENOMEM;
 	}
-	memset(chip->dma_buf, 0, 512);
-	chunk->buf = chip->dma_buf + 512;
-	chunk->addr = chip->dma_buf_addr + 512;
-	chunk->size = chip->dma_buf_size - 512;
+	memset(chip->dma.area, 0, 512);
+	chunk->buf = chip->dma.area + 512;
+	chunk->addr = chip->dma.addr + 512;
+	chunk->size = chip->dma.bytes - 512;
 	chunk->empty = 1;
 	list_add(&chunk->list, &chip->buf_list);
 
@@ -1812,7 +1815,7 @@
 
 	wave_set_register(chip, apu << 3, (memory->addr - 0x10) & 0xfff8);
 
-	pa = (unsigned int)((memory->addr - chip->dma_buf_addr) >> 1);
+	pa = (unsigned int)((memory->addr - chip->dma.addr) >> 1);
 	pa |= 0x00400000;	/* System RAM (Bit 22) */
 
 	/* initialize apu */
@@ -1902,10 +1905,10 @@
 		return err;
 
 	/* set PCMBAR */
-	wave_set_register(chip, 0x01FC, chip->dma_buf_addr >> 12);
-	wave_set_register(chip, 0x01FD, chip->dma_buf_addr >> 12);
-	wave_set_register(chip, 0x01FE, chip->dma_buf_addr >> 12);
-	wave_set_register(chip, 0x01FF, chip->dma_buf_addr >> 12);
+	wave_set_register(chip, 0x01FC, chip->dma.addr >> 12);
+	wave_set_register(chip, 0x01FD, chip->dma.addr >> 12);
+	wave_set_register(chip, 0x01FE, chip->dma.addr >> 12);
+	wave_set_register(chip, 0x01FF, chip->dma.addr >> 12);
 
 	if ((err = snd_pcm_new(chip->card, "ESS Maestro", device,
 			       chip->playback_streams,
@@ -2329,7 +2332,7 @@
 	outb(0x88, iobase+0x1f);
 
 	/* it appears some maestros (dell 7500) only work if these are set,
-	   regardless of whether we use the assp or not. */
+	   regardless of wether we use the assp or not. */
 
 	outb(0, iobase + ASSP_CONTROL_B);
 	outb(3, iobase + ASSP_CONTROL_A);	/* M: Reserved bits... */
@@ -2443,9 +2446,9 @@
 	snd_es1968_chip_init(chip);
 
 	/* need to restore the base pointers.. */ 
-	if (chip->dma_buf_addr) {
+	if (chip->dma.addr) {
 		/* set PCMBAR */
-		wave_set_register(chip, 0x01FC, chip->dma_buf_addr >> 12);
+		wave_set_register(chip, 0x01FC, chip->dma.addr >> 12);
 	}
 
 	/* restore ac97 state */
@@ -2603,7 +2606,7 @@
 	/* just to be sure */
 	pci_set_master(pci);
 
-	if (do_pm) {
+	if (do_pm > 1) {
 		/* disable power-management if not maestro2e or
 		 * if not on the whitelist
 		 */
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/Makefile linux-2.5.65-bk2/sound/pci/ice1712/Makefile
--- linux-2.5.65-bk1/sound/pci/ice1712/Makefile	Mon Mar 17 13:44:03 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/Makefile	Mon Mar 31 12:39:51 2003
@@ -3,7 +3,9 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-snd-ice1712-objs := ice1712.o ak4524.o delta.o hoontech.o ews.o amp.o
+snd-ice1712-objs := ice1712.o ak4524.o delta.o hoontech.o ews.o
+snd-ice1724-objs := ice1724.o ak4524.o amp.o revo.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o
+obj-$(CONFIG_SND_ICE1724) += snd-ice1724.o
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/ak4524.c linux-2.5.65-bk2/sound/pci/ice1712/ak4524.c
--- linux-2.5.65-bk1/sound/pci/ice1712/ak4524.c	Mon Mar 17 13:44:08 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/ak4524.c	Mon Mar 31 12:39:51 2003
@@ -1,7 +1,7 @@
 /*
  *   ALSA driver for ICEnsemble ICE1712 (Envy24)
  *
- *   AK4524 / AK4528 / AK4529 interface
+ *   AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface
  *
  *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
  *
@@ -31,25 +31,25 @@
 
 
 /*
- * write AK4524 register
+ * write AK4xxx register
  */
-void snd_ice1712_ak4524_write(ice1712_t *ice, int chip,
+void snd_ice1712_akm4xxx_write(akm4xxx_t *ak, int chip,
 			      unsigned char addr, unsigned char data)
 {
-	unsigned char tmp, saved[2];
+	unsigned int tmp;
 	int idx;
 	unsigned int addrdata;
-	ak4524_t *ak = &ice->ak4524;
+	ice1712_t *ice = ak->chip;
 
 	snd_assert(chip >= 0 && chip < 4, return);
 
 	if (ak->ops.start) {
-		if (ak->ops.start(ice, saved, chip) < 0)
+		if (ak->ops.start(ak, chip) < 0)
 			return;
 	} else
-		snd_ice1712_save_gpio_status(ice, saved);
+		snd_ice1712_save_gpio_status(ice);
 
-	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+	tmp = snd_ice1712_gpio_read(ice);
 	tmp |= ak->add_flags;
 	tmp &= ~ak->mask_flags;
 	if (ak->cs_mask == ak->cs_addr) {
@@ -57,35 +57,46 @@
 			tmp |= ak->cs_mask; /* start without chip select */
 		}  else {
 			tmp &= ~ak->cs_mask; /* chip select low */
-			snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+			snd_ice1712_gpio_write(ice, tmp);
 			udelay(1);
 		}
 	} else {
+		/* doesn't handle cf=1 yet */
 		tmp &= ~ak->cs_mask;
 		tmp |= ak->cs_addr;
+		snd_ice1712_gpio_write(ice, tmp);
+		udelay(1);
 	}
 
 	/* build I2C address + data byte */
-	addrdata = (ak->caddr << 14) | 0x2000 | ((addr & 0x0f) << 8) | data;
+	addrdata = (ak->caddr << 6) | 0x20 | (addr & 0x1f);
+	addrdata = (addrdata << 8) | data;
 	for (idx = 15; idx >= 0; idx--) {
-		tmp &= ~(ak->data_mask | ak->clk_mask);
+		/* drop clock */
+		tmp &= ~ak->clk_mask;
+		snd_ice1712_gpio_write(ice, tmp);
+		udelay(1);
+		/* set data */
 		if (addrdata & (1 << idx))
 			tmp |= ak->data_mask;
-		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
-		//udelay(200);
+		else
+			tmp &= ~ak->data_mask;
+		snd_ice1712_gpio_write(ice, tmp);
 		udelay(1);
+		/* raise clock */
 		tmp |= ak->clk_mask;
-		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		snd_ice1712_gpio_write(ice, tmp);
 		udelay(1);
 	}
 
+	/* save the data */
 	if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
 		if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0)
 			ak->images[chip][addr] = data;
 		else
 			ak->ipga_gain[chip][addr-4] = data;
 	} else {
-		/* AK4529 */
+		/* AK4529, or else */
 		ak->images[chip][addr] = data;
 	}
 	
@@ -93,7 +104,7 @@
 		if (ak->cif) {
 			/* assert a cs pulse to trigger */
 			tmp &= ~ak->cs_mask;
-			snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+			snd_ice1712_gpio_write(ice, tmp);
 			udelay(1);
 		}
 		tmp |= ak->cs_mask; /* chip select high to trigger */
@@ -101,48 +112,70 @@
 		tmp &= ~ak->cs_mask;
 		tmp |= ak->cs_none; /* deselect address */
 	}
-	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
 
 	if (ak->ops.stop)
-		ak->ops.stop(ice, saved);
+		ak->ops.stop(ak);
 	else
-		snd_ice1712_restore_gpio_status(ice, saved);
+		snd_ice1712_restore_gpio_status(ice);
 }
 
-void snd_ice1712_ak4524_reset(ice1712_t *ice, int state)
+/*
+ * reset the AKM codecs
+ * @state: 1 = reset codec, 0 = restore the registers
+ *
+ * assert the reset operation and restores the register values to the chips.
+ */
+void snd_ice1712_akm4xxx_reset(akm4xxx_t *ak, int state)
 {
 	unsigned int chip;
 	unsigned char reg;
-	ak4524_t *ak = &ice->ak4524;
 	
 	switch (ak->type) {
 	case SND_AK4524:
 	case SND_AK4528:
 		for (chip = 0; chip < ak->num_dacs/2; chip++) {
-			snd_ice1712_ak4524_write(ice, chip, 0x01, state ? 0x00 : 0x03);
+			snd_ice1712_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
 			if (state)
 				continue;
 			/* DAC volumes */
 			for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++)
-				snd_ice1712_ak4524_write(ice, chip, reg, ak->images[chip][reg]);
+				snd_ice1712_akm4xxx_write(ak, chip, reg, ak->images[chip][reg]);
 			if (ak->type == SND_AK4528)
 				continue;
 			/* IPGA */
 			for (reg = 0x04; reg < 0x06; reg++)
-				snd_ice1712_ak4524_write(ice, chip, reg, ak->ipga_gain[chip][reg-4]);
+				snd_ice1712_akm4xxx_write(ak, chip, reg, ak->ipga_gain[chip][reg-4]);
 		}
 		break;
 	case SND_AK4529:
 		/* FIXME: needed for ak4529? */
 		break;
+	case SND_AK4355:
+		snd_ice1712_akm4xxx_write(ak, 0, 0x01, state ? 0x02 : 0x01);
+		if (state)
+			return;
+		for (reg = 0x00; reg < 0x0a; reg++)
+			if (reg != 0x01)
+				snd_ice1712_akm4xxx_write(ak, 0, reg, ak->images[0][reg]);
+		break;
+	case SND_AK4381:
+		for (chip = 0; chip < ak->num_dacs/2; chip++) {
+			snd_ice1712_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
+			if (state)
+				continue;
+			for (reg = 0x01; reg < 0x05; reg++)
+				snd_ice1712_akm4xxx_write(ak, chip, reg, ak->images[chip][reg]);
+		}
+		break;
 	}
 }
 
 /*
- * initialize all the ak4524/4528 chips
+ * initialize all the ak4xxx chips
  */
-void __devinit snd_ice1712_ak4524_init(ice1712_t *ice)
+static void __devinit snd_ice1712_akm4xxx_init_chip(akm4xxx_t *ak)
 {
 	static unsigned char inits_ak4524[] = {
 		0x00, 0x07, /* 0: all power up */
@@ -184,9 +217,35 @@
 		0x08, 0x55, /* 8: deemphasis all off */
 		0xff, 0xff
 	};
+	static unsigned char inits_ak4355[] = {
+		0x01, 0x02, /* 1: reset and soft-mute */
+		0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
+		// 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
+		0x02, 0x2e,
+		0x03, 0x01, /* 3: de-emphasis off */
+		0x04, 0x00, /* 4: LOUT1 volume muted */
+		0x05, 0x00, /* 5: ROUT1 volume muted */
+		0x06, 0x00, /* 6: LOUT2 volume muted */
+		0x07, 0x00, /* 7: ROUT2 volume muted */
+		0x08, 0x00, /* 8: LOUT3 volume muted */
+		0x09, 0x00, /* 9: ROUT3 volume muted */
+		0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
+		0x01, 0x01, /* 1: un-reset, unmute */
+		0xff, 0xff
+	};
+	static unsigned char inits_ak4381[] = {
+		0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
+		// 0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */
+		0x01, 0x12,
+		0x02, 0x00, /* 2: DZF disabled */
+		0x03, 0x00, /* 3: LATT 0 */
+		0x04, 0x00, /* 4: RATT 0 */
+		0x00, 0x0f, /* 0: power-up, un-reset */
+		0xff, 0xff
+	};
+
 	int chip, num_chips;
 	unsigned char *ptr, reg, data, *inits;
-	ak4524_t *ak = &ice->ak4524;
 
 	switch (ak->type) {
 	case SND_AK4524:
@@ -198,10 +257,20 @@
 		num_chips = ak->num_dacs / 2;
 		break;
 	case SND_AK4529:
-	default:
 		inits = inits_ak4529;
 		num_chips = 1;
 		break;
+	case SND_AK4355:
+		inits = inits_ak4355;
+		num_chips = 1;
+		break;
+	case SND_AK4381:
+		inits = inits_ak4381;
+		num_chips = ak->num_dacs / 2;
+		break;
+	default:
+		snd_BUG();
+		return;
 	}
 
 	for (chip = 0; chip < num_chips; chip++) {
@@ -209,12 +278,23 @@
 		while (*ptr != 0xff) {
 			reg = *ptr++;
 			data = *ptr++;
-			snd_ice1712_ak4524_write(ice, chip, reg, data);
+			snd_ice1712_akm4xxx_write(ak, chip, reg, data);
 		}
 	}
 }
 
 
+/*
+ * initialize the akm4xxx_t record with the template
+ */
+void snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *temp, ice1712_t *ice)
+{
+	*ak = *temp;
+	ak->chip = ice;
+	snd_ice1712_akm4xxx_init_chip(ak);
+}
+
+
 #define AK_GET_CHIP(val)		(((val) >> 8) & 0xff)
 #define AK_GET_ADDR(val)		((val) & 0xff)
 #define AK_GET_SHIFT(val)		(((val) >> 16) & 0x7f)
@@ -223,7 +303,7 @@
 #define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
 #define AK_INVERT 			(1<<23)
 
-static int snd_ice1712_ak4524_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_ice1712_akm4xxx_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
 
@@ -234,22 +314,22 @@
 	return 0;
 }
 
-static int snd_ice1712_ak4524_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ice1712_akm4xxx_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
 	int invert = AK_GET_INVERT(kcontrol->private_value);
 	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
-	unsigned char val = ice->ak4524.images[chip][addr];
+	unsigned char val = ak->images[chip][addr];
 	
 	ucontrol->value.integer.value[0] = invert ? mask - val : val;
 	return 0;
 }
 
-static int snd_ice1712_ak4524_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ice1712_akm4xxx_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
 	int invert = AK_GET_INVERT(kcontrol->private_value);
@@ -259,13 +339,13 @@
 
 	if (invert)
 		nval = mask - nval;
-	change = ice->ak4524.images[chip][addr] != nval;
+	change = ak->images[chip][addr] != nval;
 	if (change)
-		snd_ice1712_ak4524_write(ice, chip, addr, nval);
+		snd_ice1712_akm4xxx_write(ak, chip, addr, nval);
 	return change;
 }
 
-static int snd_ice1712_ak4524_ipga_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_ice1712_akm4xxx_ipga_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
@@ -274,28 +354,28 @@
 	return 0;
 }
 
-static int snd_ice1712_ak4524_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ice1712_akm4xxx_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
-	ucontrol->value.integer.value[0] = ice->ak4524.ipga_gain[chip][addr-4] & 0x7f;
+	ucontrol->value.integer.value[0] = ak->ipga_gain[chip][addr-4] & 0x7f;
 	return 0;
 }
 
-static int snd_ice1712_ak4524_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ice1712_akm4xxx_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
 	unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80;
-	int change = ice->ak4524.ipga_gain[chip][addr] != nval;
+	int change = ak->ipga_gain[chip][addr] != nval;
 	if (change)
-		snd_ice1712_ak4524_write(ice, chip, addr, nval);
+		snd_ice1712_akm4xxx_write(ak, chip, addr, nval);
 	return change;
 }
 
-static int snd_ice1712_ak4524_deemphasis_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+static int snd_ice1712_akm4xxx_deemphasis_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	static char *texts[4] = {
 		"44.1kHz", "Off", "48kHz", "32kHz",
@@ -309,29 +389,29 @@
 	return 0;
 }
 
-static int snd_ice1712_ak4524_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ice1712_akm4xxx_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
 	int shift = AK_GET_SHIFT(kcontrol->private_value);
-	ucontrol->value.enumerated.item[0] = (ice->ak4524.images[chip][addr] >> shift) & 3;
+	ucontrol->value.enumerated.item[0] = (ak->images[chip][addr] >> shift) & 3;
 	return 0;
 }
 
-static int snd_ice1712_ak4524_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ice1712_akm4xxx_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol);
 	int chip = AK_GET_CHIP(kcontrol->private_value);
 	int addr = AK_GET_ADDR(kcontrol->private_value);
 	int shift = AK_GET_SHIFT(kcontrol->private_value);
 	unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
 	int change;
 	
-	nval = (nval << shift) | (ice->ak4524.images[chip][addr] & ~(3 << shift));
-	change = ice->ak4524.images[chip][addr] != nval;
+	nval = (nval << shift) | (ak->images[chip][addr] & ~(3 << shift));
+	change = ak->images[chip][addr] != nval;
 	if (change)
-		snd_ice1712_ak4524_write(ice, chip, addr, nval);
+		snd_ice1712_akm4xxx_write(ak, chip, addr, nval);
 	return change;
 }
 
@@ -339,90 +419,107 @@
  * build AK4524 controls
  */
 
-int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice)
+int __devinit snd_ice1712_akm4xxx_build_controls(ice1712_t *ice)
 {
 	unsigned int idx;
 	int err;
-	ak4524_t *ak = &ice->ak4524;
+	unsigned int akidx;
 
-	for (idx = 0; idx < ak->num_dacs; ++idx) {
-		snd_kcontrol_t ctl;
-		memset(&ctl, 0, sizeof(ctl));
-		strcpy(ctl.id.name, "DAC Volume");
-		ctl.id.index = idx;
-		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		ctl.info = snd_ice1712_ak4524_volume_info;
-		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
-		ctl.get = snd_ice1712_ak4524_volume_get;
-		ctl.put = snd_ice1712_ak4524_volume_put;
-		switch (ak->type) {
-		case SND_AK4524:
-			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */
-			break;
-		case SND_AK4528:
-			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
-			break;
-		case SND_AK4529: {
-			int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
-			ctl.private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
-			break;
+	for (akidx = 0; akidx < ice->akm_codecs; akidx++) {
+		akm4xxx_t *ak = &ice->akm[akidx];
+		for (idx = 0; idx < ak->num_dacs; ++idx) {
+			snd_kcontrol_t ctl;
+			memset(&ctl, 0, sizeof(ctl));
+			strcpy(ctl.id.name, "DAC Volume");
+			ctl.id.index = idx + ak->idx_offset * 2;
+			ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+			ctl.info = snd_ice1712_akm4xxx_volume_info;
+			ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+			ctl.get = snd_ice1712_akm4xxx_volume_get;
+			ctl.put = snd_ice1712_akm4xxx_volume_put;
+			switch (ak->type) {
+			case SND_AK4524:
+				ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */
+				break;
+			case SND_AK4528:
+				ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
+				break;
+			case SND_AK4529: {
+				int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
+				ctl.private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
+				break;
+			}
+			case SND_AK4355:
+				ctl.private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
+				break;
+			case SND_AK4381:
+				ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */
+				break;
+			default:
+				return -EINVAL;
+			}
+			ctl.private_data = ak;
+			if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
+				return err;
 		}
+		for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
+			snd_kcontrol_t ctl;
+			memset(&ctl, 0, sizeof(ctl));
+			strcpy(ctl.id.name, "ADC Volume");
+			ctl.id.index = idx;
+			ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+			ctl.info = snd_ice1712_akm4xxx_volume_info;
+			ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+			ctl.get = snd_ice1712_akm4xxx_volume_get;
+			ctl.put = snd_ice1712_akm4xxx_volume_put;
+			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
+			ctl.private_data = ak;
+			if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
+				return err;
+			memset(&ctl, 0, sizeof(ctl));
+			strcpy(ctl.id.name, "IPGA Analog Capture Volume");
+			ctl.id.index = idx;
+			ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+			ctl.info = snd_ice1712_akm4xxx_ipga_gain_info;
+			ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+			ctl.get = snd_ice1712_akm4xxx_ipga_gain_get;
+			ctl.put = snd_ice1712_akm4xxx_ipga_gain_put;
+			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */
+			ctl.private_data = ak;
+			if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
+				return err;
 		}
-		ctl.private_data = ice;
-		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
-			return err;
-	}
-	for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
-		snd_kcontrol_t ctl;
-		memset(&ctl, 0, sizeof(ctl));
-		strcpy(ctl.id.name, "ADC Volume");
-		ctl.id.index = idx;
-		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		ctl.info = snd_ice1712_ak4524_volume_info;
-		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
-		ctl.get = snd_ice1712_ak4524_volume_get;
-		ctl.put = snd_ice1712_ak4524_volume_put;
-		ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
-		ctl.private_data = ice;
-		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
-			return err;
-		memset(&ctl, 0, sizeof(ctl));
-		strcpy(ctl.id.name, "IPGA Analog Capture Volume");
-		ctl.id.index = idx;
-		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		ctl.info = snd_ice1712_ak4524_ipga_gain_info;
-		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
-		ctl.get = snd_ice1712_ak4524_ipga_gain_get;
-		ctl.put = snd_ice1712_ak4524_ipga_gain_put;
-		ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */
-		ctl.private_data = ice;
-		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
-			return err;
-	}
-	for (idx = 0; idx < ak->num_dacs/2; idx++) {
-		snd_kcontrol_t ctl;
-		memset(&ctl, 0, sizeof(ctl));
-		strcpy(ctl.id.name, "Deemphasis");
-		ctl.id.index = idx;
-		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		ctl.info = snd_ice1712_ak4524_deemphasis_info;
-		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
-		ctl.get = snd_ice1712_ak4524_deemphasis_get;
-		ctl.put = snd_ice1712_ak4524_deemphasis_put;
-		switch (ak->type) {
-		case SND_AK4524:
-		case SND_AK4528:
-			ctl.private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */
-			break;
-		case SND_AK4529: {
-			int shift = idx == 3 ? 6 : (2 - idx) * 2;
-			ctl.private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */
-			break;
-		}
+		for (idx = 0; idx < ak->num_dacs/2; idx++) {
+			snd_kcontrol_t ctl;
+			memset(&ctl, 0, sizeof(ctl));
+			strcpy(ctl.id.name, "Deemphasis");
+			ctl.id.index = idx + ak->idx_offset;
+			ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+			ctl.info = snd_ice1712_akm4xxx_deemphasis_info;
+			ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+			ctl.get = snd_ice1712_akm4xxx_deemphasis_get;
+			ctl.put = snd_ice1712_akm4xxx_deemphasis_put;
+			switch (ak->type) {
+			case SND_AK4524:
+			case SND_AK4528:
+				ctl.private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */
+				break;
+			case SND_AK4529: {
+				int shift = idx == 3 ? 6 : (2 - idx) * 2;
+				ctl.private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */
+				break;
+			}
+			case SND_AK4355:
+				ctl.private_value = AK_COMPOSE(idx, 3, 0, 0);
+				break;
+			case SND_AK4381:
+				ctl.private_value = AK_COMPOSE(idx, 1, 1, 0);
+				break;
+			}
+			ctl.private_data = ak;
+			if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
+				return err;
 		}
-		ctl.private_data = ice;
-		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
-			return err;
 	}
 	return 0;
 }
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/amp.h linux-2.5.65-bk2/sound/pci/ice1712/amp.h
--- linux-2.5.65-bk1/sound/pci/ice1712/amp.h	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/amp.h	Mon Mar 31 12:39:51 2003
@@ -24,7 +24,7 @@
  *
  */      
 
-#define  AMP_AUDIO2000_DEVICE_DESC 	       "{AMP Ltd AUDIO2000},"
+#define  AMP_AUDIO2000_DEVICE_DESC 	       "{AMP Ltd,AUDIO2000},"
 
 #define VT1724_SUBDEVICE_AUDIO2000	0x12142417	/* Advanced Micro Peripherals Ltd AUDIO2000 */
 
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/delta.c linux-2.5.65-bk2/sound/pci/ice1712/delta.c
--- linux-2.5.65-bk1/sound/pci/ice1712/delta.c	Mon Mar 17 13:43:40 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/delta.c	Mon Mar 31 12:39:51 2003
@@ -232,32 +232,33 @@
 /*
  * AK4524 on Delta 44 and 66 to choose the chip mask
  */
-static int delta_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+static int delta_ak4524_start(akm4xxx_t *ak, int chip)
 {
-	snd_ice1712_save_gpio_status(ice, saved);
-	ice->ak4524.cs_mask =
-	ice->ak4524.cs_addr = chip == 0 ? ICE1712_DELTA_CODEC_CHIP_A :
-					  ICE1712_DELTA_CODEC_CHIP_B;
+	snd_ice1712_save_gpio_status(ak->chip);
+	ak->cs_mask =
+	ak->cs_addr = chip == 0 ? ICE1712_DELTA_CODEC_CHIP_A :
+				  ICE1712_DELTA_CODEC_CHIP_B;
 	return 0;
 }
 
 /*
  * AK4524 on Delta1010LT to choose the chip address
  */
-static int delta1010lt_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+static int delta1010lt_ak4524_start(akm4xxx_t *ak, int chip)
 {
-	snd_ice1712_save_gpio_status(ice, saved);
-	ice->ak4524.cs_mask = ICE1712_DELTA_1010LT_CS;
-	ice->ak4524.cs_addr = chip << 4;
+	snd_ice1712_save_gpio_status(ak->chip);
+	ak->cs_mask = ICE1712_DELTA_1010LT_CS;
+	ak->cs_addr = chip << 4;
 	return 0;
 }
 
 /*
  * change the rate of AK4524 on Delta 44/66, AP, 1010LT
  */
-static void delta_ak4524_set_rate_val(ice1712_t *ice, unsigned int rate)
+static void delta_ak4524_set_rate_val(akm4xxx_t *ak, unsigned int rate)
 {
 	unsigned char tmp, tmp2;
+	ice1712_t *ice = ak->chip;
 
 	if (rate == 0)	/* no hint - S/PDIF input is master, simply return */
 		return;
@@ -274,14 +275,14 @@
 		return;
 
 	/* do it again */
-	snd_ice1712_ak4524_reset(ice, 1);
+	snd_ice1712_akm4xxx_reset(ak, 1);
 	down(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS;
 	if (rate > 48000)
 		tmp |= ICE1712_DELTA_DFS;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
 	up(&ice->gpio_mutex);
-	snd_ice1712_ak4524_reset(ice, 0);
+	snd_ice1712_akm4xxx_reset(ak, 0);
 }
 
 
@@ -296,7 +297,7 @@
 }
 
 /* set up */
-static void delta_setup_spdif(ice1712_t *ice, snd_pcm_substream_t * substream)
+static void delta_setup_spdif(ice1712_t *ice, int rate)
 {
 	unsigned long flags;
 	unsigned int tmp;
@@ -306,7 +307,7 @@
 	tmp = ice->spdif.cs8403_stream_bits;
 	if (tmp & 0x01)		/* consumer */
 		tmp &= (tmp & 0x01) ? ~0x06 : ~0x18;
-	switch (substream->runtime->rate) {
+	switch (rate) {
 	case 32000: tmp |= (tmp & 0x01) ? 0x04 : 0x00; break;
 	case 44100: tmp |= (tmp & 0x01) ? 0x00 : 0x10; break;
 	case 48000: tmp |= (tmp & 0x01) ? 0x02 : 0x08; break;
@@ -325,10 +326,84 @@
  * initialize the chips on M-Audio cards
  */
 
+static akm4xxx_t akm_audiophile __devinitdata = {
+	.type = SND_AK4528,
+	.num_adcs = 2,
+	.num_dacs = 2,
+	.caddr = 2,
+	.cif = 0,
+	.data_mask = ICE1712_DELTA_AP_DOUT,
+	.clk_mask = ICE1712_DELTA_AP_CCLK,
+	.cs_mask = ICE1712_DELTA_AP_CS_CODEC,
+	.cs_addr = ICE1712_DELTA_AP_CS_CODEC,
+	.cs_none = 0,
+	.add_flags = ICE1712_DELTA_AP_CS_DIGITAL,
+	.mask_flags = 0,
+	.ops = {
+		.set_rate_val = delta_ak4524_set_rate_val
+	}
+};
+
+static akm4xxx_t akm_delta410 __devinitdata = {
+	.type = SND_AK4529,
+	.num_adcs = 2,
+	.num_dacs = 8,
+	.caddr = 0,
+	.cif = 0,
+	.data_mask = ICE1712_DELTA_AP_DOUT,
+	.clk_mask = ICE1712_DELTA_AP_CCLK,
+	.cs_mask = ICE1712_DELTA_AP_CS_CODEC,
+	.cs_addr = ICE1712_DELTA_AP_CS_CODEC,
+	.cs_none = 0,
+	.add_flags = ICE1712_DELTA_AP_CS_DIGITAL,
+	.mask_flags = 0,
+	.ops = {
+		.set_rate_val = delta_ak4524_set_rate_val
+	}
+};
+
+static akm4xxx_t akm_delta1010lt __devinitdata = {
+	.type = SND_AK4524,
+	.num_adcs = 8,
+	.num_dacs = 8,
+	.caddr = 2,
+	.cif = 0, /* the default level of the CIF pin from AK4524 */
+	.data_mask = ICE1712_DELTA_1010LT_DOUT,
+	.clk_mask = ICE1712_DELTA_1010LT_CCLK,
+	.cs_mask = 0,
+	.cs_addr = 0, /* set later */
+	.cs_none = ICE1712_DELTA_1010LT_CS_NONE,
+	.add_flags = 0,
+	.mask_flags = 0,
+	.ops = {
+		.start = delta1010lt_ak4524_start,
+		.set_rate_val = delta_ak4524_set_rate_val
+	}
+};
+
+static akm4xxx_t akm_delta44 __devinitdata = {
+	.type = SND_AK4524,
+	.num_adcs = 4,
+	.num_dacs = 4,
+	.caddr = 2,
+	.cif = 0, /* the default level of the CIF pin from AK4524 */
+	.data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA,
+	.clk_mask = ICE1712_DELTA_CODEC_SERIAL_CLOCK,
+	.cs_mask = 0,
+	.cs_addr = 0, /* set later */
+	.cs_none = 0,
+	.add_flags = 0,
+	.mask_flags = 0,
+	.ops = {
+		.start = delta_ak4524_start,
+		.set_rate_val = delta_ak4524_set_rate_val
+	}
+};
+
 static int __devinit snd_ice1712_delta_init(ice1712_t *ice)
 {
 	int err;
-	ak4524_t *ak;
+	akm4xxx_t *ak;
 
 	/* determine I2C, DACs and ADCs */
 	switch (ice->eeprom.subvendor) {
@@ -366,7 +441,7 @@
 	case ICE1712_SUBDEVICE_DELTADIO2496:
 	case ICE1712_SUBDEVICE_DELTA66:
 		ice->spdif.ops.open = delta_open_spdif;
-		ice->spdif.ops.setup = delta_setup_spdif;
+		ice->spdif.ops.setup_rate = delta_setup_spdif;
 		ice->spdif.ops.default_get = delta_spdif_default_get;
 		ice->spdif.ops.default_put = delta_spdif_default_put;
 		ice->spdif.ops.stream_get = delta_spdif_stream_get;
@@ -376,60 +451,36 @@
 		break;
 	}
 
+	/* no analog? */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_DELTA1010:
+	case ICE1712_SUBDEVICE_DELTADIO2496:
+		return 0;
+	}
+
 	/* second stage of initialization, analog parts and others */
-	ak = &ice->ak4524;
+	ak = ice->akm = kmalloc(sizeof(akm4xxx_t), GFP_KERNEL);
+	if (! ak)
+		return -ENOMEM;
+	ice->akm_codecs = 1;
+
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
+		snd_ice1712_akm4xxx_init(ak, &akm_audiophile, ice);
+		break;
 	case ICE1712_SUBDEVICE_DELTA410:
-		ak->num_adcs = ak->num_dacs = 2;
-		ak->type = SND_AK4528;
-		ak->caddr = 2;
-		if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DELTA410) {
-			ak->num_dacs = 8;
-			ak->type = SND_AK4529;
-			ak->caddr = 0;
-		}
-		ak->cif = 0; /* the default level of the CIF pin from AK4528/4529 */
-		ak->data_mask = ICE1712_DELTA_AP_DOUT;
-		ak->clk_mask = ICE1712_DELTA_AP_CCLK;
-		ak->cs_mask = ak->cs_addr = ICE1712_DELTA_AP_CS_CODEC; /* select AK4528/4529 codec */
-		ak->cs_none = 0;
-		ak->add_flags = ICE1712_DELTA_AP_CS_DIGITAL; /* assert digital high */
-		ak->mask_flags = 0;
-		ak->ops.set_rate_val = delta_ak4524_set_rate_val;
-		snd_ice1712_ak4524_init(ice);
+		snd_ice1712_akm4xxx_init(ak, &akm_delta410, ice);
 		break;
 	case ICE1712_SUBDEVICE_DELTA1010LT:
-		ak->num_adcs = ak->num_dacs = 8;
-		ak->type = SND_AK4524;
-		ak->caddr = 2;
-		ak->cif = 0; /* the default level of the CIF pin from AK4524 */
-		ak->data_mask = ICE1712_DELTA_1010LT_DOUT;
-		ak->clk_mask = ICE1712_DELTA_1010LT_CCLK;
-		ak->cs_mask = ak->cs_addr = 0; /* set later */
-		ak->cs_none = ICE1712_DELTA_1010LT_CS_NONE;
-		ak->add_flags = 0;
-		ak->mask_flags = 0;
-		ak->ops.start = delta1010lt_ak4524_start;
-		ak->ops.set_rate_val = delta_ak4524_set_rate_val;
-		snd_ice1712_ak4524_init(ice);
+		snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, ice);
 		break;
 	case ICE1712_SUBDEVICE_DELTA66:
 	case ICE1712_SUBDEVICE_DELTA44:
-		ak->num_adcs = ak->num_dacs = 4;
-		ak->type = SND_AK4524;
-		ak->caddr = 2;
-		ak->cif = 0; /* the default level of the CIF pin from AK4524 */
-		ak->data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA;
-		ak->clk_mask = ICE1712_DELTA_CODEC_SERIAL_CLOCK;
-		ak->cs_mask = ak->cs_addr = 0; /* set later */
-		ak->cs_none = 0;
-		ak->add_flags = 0;
-		ak->mask_flags = 0;
-		ak->ops.start = delta_ak4524_start;
-		ak->ops.set_rate_val = delta_ak4524_set_rate_val;
-		snd_ice1712_ak4524_init(ice);
+		snd_ice1712_akm4xxx_init(ak, &akm_delta44, ice);
 		break;
+	default:
+		snd_BUG();
+		return -EINVAL;
 	}
 
 	return 0;
@@ -510,7 +561,7 @@
 	case ICE1712_SUBDEVICE_DELTA410:
 	case ICE1712_SUBDEVICE_DELTA44:
 	case ICE1712_SUBDEVICE_DELTA66:
-		err = snd_ice1712_ak4524_build_controls(ice);
+		err = snd_ice1712_akm4xxx_build_controls(ice);
 		if (err < 0)
 			return err;
 		break;
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/envy24ht.h linux-2.5.65-bk2/sound/pci/ice1712/envy24ht.h
--- linux-2.5.65-bk1/sound/pci/ice1712/envy24ht.h	Mon Mar 17 13:44:51 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/envy24ht.h	Mon Mar 31 12:39:51 2003
@@ -29,6 +29,23 @@
 #include <sound/pcm.h>
 
 #include "ice1712.h"
+
+enum {
+	ICE_EEP2_SYSCONF = 0,	/* 06 */
+	ICE_EEP2_ACLINK,	/* 07 */
+	ICE_EEP2_I2S,		/* 08 */
+	ICE_EEP2_SPDIF,		/* 09 */
+	ICE_EEP2_GPIO_DIR,	/* 0a */
+	ICE_EEP2_GPIO_DIR1,	/* 0b */
+	ICE_EEP2_GPIO_DIR2,	/* 0c */
+	ICE_EEP2_GPIO_MASK,	/* 0d */
+	ICE_EEP2_GPIO_MASK1,	/* 0e */
+	ICE_EEP2_GPIO_MASK2,	/* 0f */
+	ICE_EEP2_GPIO_STATE,	/* 10 */
+	ICE_EEP2_GPIO_STATE1,	/* 11 */
+	ICE_EEP2_GPIO_STATE2	/* 12 */
+};
+	
 /*
  *  Direct registers
  */
@@ -72,13 +89,6 @@
 /*there is no consumer AC97 codec with the VT1724*/
 //#define VT1724_REG_AC97_INDEX		0x08	/* byte */
 //#define VT1724_REG_AC97_CMD		0x09	/* byte */
-#define   VT1724_AC97_COLD		0x80	/* cold reset */
-#define   VT1724_AC97_WARM		0x40	/* warm reset */
-#define   VT1724_AC97_WRITE		0x20	/* W: write, R: write in progress */
-#define   VT1724_AC97_READ		0x10	/* W: read, R: read in progress */
-#define   VT1724_AC97_READY		0x08	/* codec ready status bit */
-#define   VT1724_AC97_PBK_VSR		0x02	/* playback VSR */
-#define   VT1724_AC97_CAP_VSR		0x01	/* capture VSR */
 
 #define VT1724_REG_MPU_TXFIFO		0x0a	/*byte ro. number of bytes in TX fifo*/
 #define VT1724_REG_MPU_RXFIFO		0x0b	/*byte ro. number of bytes in RX fifo*/
@@ -100,12 +110,12 @@
 #define   VT1724_I2C_BUSY		0x01	/* busy bit */
 
 #define VT1724_REG_GPIO_DATA	0x14	/* word */
-#define VT1724_REG_GPIO_WRITE_MASK	0x15 /* word */
-#define VT1724_REG_GPIO_DIRECTION	0x16 /* dword? (3 bytes) 0=input 1=output. 
-							bit3 - during reset used for Eeprom power-on strapping
-							if TESTEN# pin active, bit 2 always input*/
+#define VT1724_REG_GPIO_WRITE_MASK	0x16 /* word */
+#define VT1724_REG_GPIO_DIRECTION	0x18 /* dword? (3 bytes) 0=input 1=output. 
+						bit3 - during reset used for Eeprom power-on strapping
+						if TESTEN# pin active, bit 2 always input*/
 #define VT1724_REG_POWERDOWN	0x1c
-#define VT1724_REG_GPIO_DIRECTION_22	0x1e /* byte direction for GPIO 16:22 */
+#define VT1724_REG_GPIO_DATA_22	0x1e /* byte direction for GPIO 16:22 */
 #define VT1724_REG_GPIO_WRITE_MASK_22	0x1f /* byte write mask for GPIO 16:22 */
 
 
@@ -128,15 +138,24 @@
 #define VT1724_MT_RATE			0x01	/* byte - sampling rate select */
 #define   VT1724_SPDIF_MASTER		0x10	/* S/PDIF input is master clock */
 #define VT1724_MT_I2S_FORMAT		0x02	/* byte - I2S data format */
+#define   VT1724_MT_I2S_MCLK_128X	0x08
+#define   VT1724_MT_I2S_FORMAT_MASK	0x03
+#define   VT1724_MT_I2S_FORMAT_I2S	0x00
 #define VT1724_MT_DMA_INT_MASK		0x03	/* byte -DMA Interrupt Mask */
 /* lool to VT1724_MULTI_* */
 #define VT1724_MT_AC97_INDEX		0x04	/* byte - AC'97 index */
 #define VT1724_MT_AC97_CMD		0x05	/* byte - AC'97 command & status */
-/* look to VT1724_AC97_* */
+#define   VT1724_AC97_COLD	0x80	/* cold reset */
+#define   VT1724_AC97_WARM	0x40	/* warm reset */
+#define   VT1724_AC97_WRITE	0x20	/* W: write, R: write in progress */
+#define   VT1724_AC97_READ	0x10	/* W: read, R: read in progress */
+#define   VT1724_AC97_READY	0x08	/* codec ready status bit */
+#define   VT1724_AC97_PBK_VSR	0x02	/* playback VSR */
+#define   VT1724_AC97_CAP_VSR	0x01	/* capture VSR */
 #define VT1724_MT_AC97_DATA		0x06	/* word - AC'97 data */
-#define VT1724_MT_PLAYBACK_ADDR	0x10	/* dword - playback address */
-#define VT1724_MT_PLAYBACK_SIZE	0x14	/* dword - playback size */
-#define VT1724_MT_PLAYBACK_CONTROL	0x18	/* byte - control */
+#define VT1724_MT_PLAYBACK_ADDR		0x10	/* dword - playback address */
+#define VT1724_MT_PLAYBACK_SIZE		0x14	/* dword - playback size */
+#define VT1724_MT_DMA_CONTROL		0x18	/* byte - control */
 #define   VT1724_PDMA4_START	0x80	/* SPDIF out / PDMA4 start */
 #define   VT1724_PDMA3_START	0x40	/* PDMA3 start */
 #define   VT1724_PDMA2_START	0x20	/* PDMA2 start */
@@ -145,14 +164,14 @@
 #define   VT1724_RDMA0_START	0x02	/* RMDA0 start */
 #define   VT1724_PDMA0_START	0x01	/* MC Interleave / PDMA0 start */
 #define VT1724_MT_BURST			0x19	/* Interleaved playback DMA Active streams / PCI burst size */
-#define VT1724_MT_DMA_FIFO_ERR	0x1a	/*Global playback and record DMA FIFO Underrun/Overrun */
-#define   VT1724_PDMA4_UNDERRUN	0x80
-#define   VT1724_PDMA2_UNDERRUN	0x40
-#define   VT1724_PDMA3_UNDERRUN	0x20
-#define   VT1724_PDMA1_UNDERRUN	0x10
-#define   VT1724_RDMA1_UNDERRUN	0x04
-#define   VT1724_RDMA0_UNDERRUN	0x02
-#define   VT1724_PDMA0_UNDERRUN	0x01
+#define VT1724_MT_DMA_FIFO_ERR		0x1a	/*Global playback and record DMA FIFO Underrun/Overrun */
+#define   VT1724_PDMA4_UNDERRUN		0x80
+#define   VT1724_PDMA2_UNDERRUN		0x40
+#define   VT1724_PDMA3_UNDERRUN		0x20
+#define   VT1724_PDMA1_UNDERRUN		0x10
+#define   VT1724_RDMA1_UNDERRUN		0x04
+#define   VT1724_RDMA0_UNDERRUN		0x02
+#define   VT1724_PDMA0_UNDERRUN		0x01
 #define VT1724_MT_DMA_PAUSE		0x1b	/*Global playback and record DMA FIFO pause/resume */
 #define	  VT1724_PDMA4_PAUSE	0x80
 #define	  VT1724_PDMA3_PAUSE	0x40
@@ -164,40 +183,31 @@
 #define VT1724_MT_PLAYBACK_COUNT	0x1c	/* word - playback count */
 #define VT1724_MT_CAPTURE_ADDR		0x20	/* dword - capture address */
 #define VT1724_MT_CAPTURE_SIZE		0x24	/* word - capture size */
-#define VT1724_MT_CAPTURE_COUNT	0x26	/* word - capture count */
-
-#define VT1724_MT_RDMA1_ADDR	0x30	/* dword - RDMA1 capture address */
-#define VT1724_MT_RDMA1_SIZE	0x34	/* word - RDMA1 capture size */
-#define VT1724_MT_RDMA1_COUNT	0x36	/* word - RDMA1 capture count */
+#define VT1724_MT_CAPTURE_COUNT		0x26	/* word - capture count */
 
 #define VT1724_MT_ROUTE_PLAYBACK	0x2c	/* word */
-//#define VT1724_MT_MONITOR_VOLUME	0x3f	/* word */
-//#define VT1724_MT_MONITOR_INDEX	0x3e	/* byte */
 
+#define VT1724_MT_RDMA1_ADDR		0x30	/* dword - RDMA1 capture address */
+#define VT1724_MT_RDMA1_SIZE		0x34	/* word - RDMA1 capture size */
+#define VT1724_MT_RDMA1_COUNT		0x36	/* word - RDMA1 capture count */
 
-#define VT1724_MT_PDMA4_ADDR	0x40	/* dword */
-#define VT7124_MT_PDMA4_SIZE	0x44	/* word */
-#define VT1724_MT_PDMA4_COUNT	0x46	/* word */
-#define VT1724_MT_PDMA3_ADDR	0x50	/* dword */
-#define VT7124_MT_PDMA3_SIZE	0x54	/* word */
-#define VT1724_MT_PDMA3_COUNT	0x56	/* word */
-#define VT1724_MT_PDMA2_ADDR	0x60	/* dword */
-#define VT7124_MT_PDMA2_SIZE	0x64	/* word */
-#define VT1724_MT_PDMA2_COUNT	0x66	/* word */
-#define VT1724_MT_PDMA1_ADDR	0x70	/* dword */
-#define VT7124_MT_PDMA1_SIZE	0x74	/* word */
-#define VT1724_MT_PDMA1_COUNT	0x76	/* word */
-
-
-//does VT1724 have these? don't think so
-//#define VT1724_MT_MONITOR_RATE		0x3b	/* byte */
-//#define VT1724_MT_MONITOR_ROUTECTRL	0x3c	/* byte */
-//#define   VT1724_ROUTE_AC97		0x01	/* route digital mixer output to AC'97 */
+#define VT1724_MT_SPDIF_CTRL		0x3c	/* word */
 #define VT1724_MT_MONITOR_PEAKINDEX	0x3e	/* byte */
 #define VT1724_MT_MONITOR_PEAKDATA	0x3f	/* byte */
 
-
-
+/* concurrent stereo channels */
+#define VT1724_MT_PDMA4_ADDR		0x40	/* dword */
+#define VT1724_MT_PDMA4_SIZE		0x44	/* word */
+#define VT1724_MT_PDMA4_COUNT		0x46	/* word */
+#define VT1724_MT_PDMA3_ADDR		0x50	/* dword */
+#define VT1724_MT_PDMA3_SIZE		0x54	/* word */
+#define VT1724_MT_PDMA3_COUNT		0x56	/* word */
+#define VT1724_MT_PDMA2_ADDR		0x60	/* dword */
+#define VT1724_MT_PDMA2_SIZE		0x64	/* word */
+#define VT1724_MT_PDMA2_COUNT		0x66	/* word */
+#define VT1724_MT_PDMA1_ADDR		0x70	/* dword */
+#define VT1724_MT_PDMA1_SIZE		0x74	/* word */
+#define VT1724_MT_PDMA1_COUNT		0x76	/* word */
 
 
 #endif /* __SOUND_VT1724_H */
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/ews.c linux-2.5.65-bk2/sound/pci/ice1712/ews.c
--- linux-2.5.65-bk1/sound/pci/ice1712/ews.c	Mon Mar 17 13:43:48 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/ews.c	Mon Mar 31 12:39:51 2003
@@ -83,7 +83,7 @@
 	ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return);
 	unsigned char mask;
 
-	snd_ice1712_save_gpio_status(ice, (unsigned char *)&bus->private_value);
+	snd_ice1712_save_gpio_status(ice);
 	/* set RW high */
 	mask = ICE1712_EWX2496_RW;
 	switch (ice->eeprom.subvendor) {
@@ -100,7 +100,7 @@
 static void ewx_i2c_stop(snd_i2c_bus_t *bus)
 {
 	ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return);
-	snd_ice1712_restore_gpio_status(ice, (unsigned char *)&bus->private_value);
+	snd_ice1712_restore_gpio_status(ice);
 }
 
 static void ewx_i2c_direction(snd_i2c_bus_t *bus, int clock, int data)
@@ -112,9 +112,9 @@
 		mask |= ICE1712_EWX2496_SERIAL_CLOCK; /* write SCL */
 	if (data)
 		mask |= ICE1712_EWX2496_SERIAL_DATA; /* write SDA */
-	ice->gpio_direction &= ~(ICE1712_EWX2496_SERIAL_CLOCK|ICE1712_EWX2496_SERIAL_DATA);
-	ice->gpio_direction |= mask;
-	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio_direction);
+	ice->gpio.direction &= ~(ICE1712_EWX2496_SERIAL_CLOCK|ICE1712_EWX2496_SERIAL_DATA);
+	ice->gpio.direction |= mask;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio.direction);
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~mask);
 }
 
@@ -155,56 +155,60 @@
 }
 
 /* start callback for EWS88MT, needs to select a certain chip mask */
-static int ews88mt_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+static int ews88mt_ak4524_start(akm4xxx_t *ak, int chip)
 {
+	ice1712_t *ice = ak->chip;
 	unsigned char tmp;
 	/* assert AK4524 CS */
 	if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0)
 		return -EINVAL;
-	snd_ice1712_save_gpio_status(ice, saved);
+	snd_ice1712_save_gpio_status(ice);
 	tmp = ICE1712_EWS88_SERIAL_DATA |
 		ICE1712_EWS88_SERIAL_CLOCK |
 		ICE1712_EWS88_RW;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
-			  ice->gpio_direction | tmp);
+			  ice->gpio.direction | tmp);
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
 	return 0;
 }
 
 /* stop callback for EWS88MT, needs to deselect chip mask */
-static void ews88mt_ak4524_stop(ice1712_t *ice, unsigned char *saved)
+static void ews88mt_ak4524_stop(akm4xxx_t *ak)
 {
-	snd_ice1712_restore_gpio_status(ice, saved);
+	ice1712_t *ice = ak->chip;
+	snd_ice1712_restore_gpio_status(ice);
 	udelay(1);
 	snd_ice1712_ews88mt_chip_select(ice, 0x0f);
 }
 
 /* start callback for EWX24/96 */
-static int ewx2496_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+static int ewx2496_ak4524_start(akm4xxx_t *ak, int chip)
 {
+	ice1712_t *ice = ak->chip;
 	unsigned char tmp;
-	snd_ice1712_save_gpio_status(ice, saved);
+	snd_ice1712_save_gpio_status(ice);
 	tmp =  ICE1712_EWX2496_SERIAL_DATA |
 		ICE1712_EWX2496_SERIAL_CLOCK |
 		ICE1712_EWX2496_AK4524_CS |
 		ICE1712_EWX2496_RW;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
-			  ice->gpio_direction | tmp);
+			  ice->gpio.direction | tmp);
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
 	return 0;
 }
 
 /* start callback for DMX 6fire */
-static int dmx6fire_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+static int dmx6fire_ak4524_start(akm4xxx_t *ak, int chip)
 {
+	ice1712_t *ice = ak->chip;
 	unsigned char tmp;
-	snd_ice1712_save_gpio_status(ice, saved);
-	tmp = ice->ak4524.cs_mask = ice->ak4524.cs_addr = (1 << chip) & ICE1712_6FIRE_AK4524_CS_MASK;
+	snd_ice1712_save_gpio_status(ice);
+	tmp = ak->cs_mask = ak->cs_addr = (1 << chip) & ICE1712_6FIRE_AK4524_CS_MASK;
 	tmp |= ICE1712_6FIRE_SERIAL_DATA |
 		ICE1712_6FIRE_SERIAL_CLOCK |
 		ICE1712_6FIRE_RW;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
-			  ice->gpio_direction | tmp);
+			  ice->gpio.direction | tmp);
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
 	return 0;
 }
@@ -221,6 +225,7 @@
 	snd_i2c_lock(ice->i2c);
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_EWS88MT:
+	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 		snd_runtime_check(snd_i2c_sendbytes(ice->cs8404, &bits, 1) == 1, goto _error);
 		break;
 	case ICE1712_SUBDEVICE_EWS88D:
@@ -292,7 +297,7 @@
 }
 
 /* set up SPDIF for EWS88MT / EWS88D */
-static void ews88_setup_spdif(ice1712_t *ice, snd_pcm_substream_t * substream)
+static void ews88_setup_spdif(ice1712_t *ice, int rate)
 {
 	unsigned long flags;
 	unsigned char tmp;
@@ -302,7 +307,7 @@
 	tmp = ice->spdif.cs8403_stream_bits;
 	if (tmp & 0x10)		/* consumer */
 		tmp &= (tmp & 0x01) ? ~0x06 : ~0x60;
-	switch (substream->runtime->rate) {
+	switch (rate) {
 	case 32000: tmp |= (tmp & 0x01) ? 0x02 : 0x00; break;
 	case 44100: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
 	case 48000: tmp |= (tmp & 0x01) ? 0x04 : 0x20; break;
@@ -318,13 +323,71 @@
 
 
 /*
+ */
+static akm4xxx_t akm_ews88mt __devinitdata = {
+	.num_adcs = 8,
+	.num_dacs = 8,
+	.type = SND_AK4524,
+	.caddr = 2,
+	.cif = 1, /* CIF high */
+	.data_mask = ICE1712_EWS88_SERIAL_DATA,
+	.clk_mask = ICE1712_EWS88_SERIAL_CLOCK,
+	.cs_mask = 0,
+	.cs_addr = 0,
+	.cs_none = 0, /* no chip select on gpio */
+	.add_flags = ICE1712_EWS88_RW, /* set rw bit high */
+	.mask_flags = 0,
+	.ops = {
+		.start = ews88mt_ak4524_start,
+		.stop = ews88mt_ak4524_stop
+	}
+};
+
+static akm4xxx_t akm_ewx2496 __devinitdata = {
+	.num_adcs = 2,
+	.num_dacs = 2,
+	.type = SND_AK4524,
+	.caddr = 2,
+	.cif = 1, /* CIF high */
+	.data_mask = ICE1712_EWS88_SERIAL_DATA,
+	.clk_mask = ICE1712_EWS88_SERIAL_CLOCK,
+	.cs_mask = ICE1712_EWX2496_AK4524_CS,
+	.cs_addr = ICE1712_EWX2496_AK4524_CS,
+	.cs_none = 0,
+	.add_flags = ICE1712_EWS88_RW, /* set rw bit high */
+	.mask_flags = 0,
+	.ops = {
+		.start = ewx2496_ak4524_start
+	}
+};
+
+static akm4xxx_t akm_6fire __devinitdata = {
+	.num_adcs = 6,
+	.num_dacs = 6,
+	.type = SND_AK4524,
+	.caddr = 2,
+	.cif = 1, /* CIF high */
+	.data_mask = ICE1712_6FIRE_SERIAL_DATA,
+	.clk_mask = ICE1712_6FIRE_SERIAL_CLOCK,
+	.cs_mask = 0,
+	.cs_addr = 0, /* set later */
+	.cs_none = 0,
+	.add_flags = ICE1712_6FIRE_RW, /* set rw bit high */
+	.mask_flags = 0,
+	.ops = {
+		.start = dmx6fire_ak4524_start
+	}
+};
+
+
+/*
  * initialize the chip
  */
 
 static int __devinit snd_ice1712_ews_init(ice1712_t *ice)
 {
 	int err;
-	ak4524_t *ak;
+	akm4xxx_t *ak;
 
 	/* set the analog DACs */
 	switch (ice->eeprom.subvendor) {
@@ -332,6 +395,7 @@
 		ice->num_total_dacs = 2;
 		break;	
 	case ICE1712_SUBDEVICE_EWS88MT:
+	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 		ice->num_total_dacs = 8;
 		break;
 	case ICE1712_SUBDEVICE_EWS88D:
@@ -358,6 +422,7 @@
 		}
 		break;
 	case ICE1712_SUBDEVICE_EWS88MT:
+	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 		if ((err = snd_i2c_device_create(ice->i2c, "CS8404", ICE1712_EWS88MT_CS8404_ADDR, &ice->cs8404)) < 0)
 			return err;
 		if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)", ICE1712_EWS88MT_INPUT_ADDR, &ice->i2cdevs[0])) < 0)
@@ -380,16 +445,16 @@
 		if ((err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR)) < 0)
 			return err;
 		break;
-#if 0 // XXX not working...
 	case ICE1712_SUBDEVICE_DMX6FIRE:
 		if ((err = snd_ice1712_init_cs8427(ice, ICE1712_6FIRE_CS8427_ADDR)) < 0)
 			return err;
-#endif
+		break;
 	case ICE1712_SUBDEVICE_EWS88MT:
+	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_EWS88D:
 		/* set up CS8404 */
 		ice->spdif.ops.open = ews88_open_spdif;
-		ice->spdif.ops.setup = ews88_setup_spdif;
+		ice->spdif.ops.setup_rate = ews88_setup_spdif;
 		ice->spdif.ops.default_get = ews88_spdif_default_get;
 		ice->spdif.ops.default_put = ews88_spdif_default_put;
 		ice->spdif.ops.stream_get = ews88_spdif_stream_get;
@@ -399,50 +464,28 @@
 		break;
 	}
 
+	/* no analog? */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_EWS88D:
+		return 0;
+	}
+
 	/* analog section */
-	ak = &ice->ak4524;
+	ak = ice->akm = kmalloc(sizeof(akm4xxx_t), GFP_KERNEL);
+	if (! ak)
+		return -ENOMEM;
+	ice->akm_codecs = 1;
+
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_EWS88MT:
-		ak->num_adcs = ak->num_dacs = 8;
-		ak->type = SND_AK4524;
-		ak->caddr = 2;
-		ak->cif = 1; /* CIF high */
-		ak->data_mask = ICE1712_EWS88_SERIAL_DATA;
-		ak->clk_mask = ICE1712_EWS88_SERIAL_CLOCK;
-		ak->cs_mask = ak->cs_addr = ak->cs_none = 0; /* no chip select on gpio */
-		ak->add_flags = ICE1712_EWS88_RW; /* set rw bit high */
-		ak->mask_flags = 0;
-		ak->ops.start = ews88mt_ak4524_start;
-		ak->ops.stop = ews88mt_ak4524_stop;
-		snd_ice1712_ak4524_init(ice);
+	case ICE1712_SUBDEVICE_EWS88MT_NEW:
+		snd_ice1712_akm4xxx_init(ak, &akm_ews88mt, ice);
 		break;
 	case ICE1712_SUBDEVICE_EWX2496:
-		ak->num_adcs = ak->num_dacs = 2;
-		ak->type = SND_AK4524;
-		ak->caddr = 2;
-		ak->cif = 1; /* CIF high */
-		ak->data_mask = ICE1712_EWS88_SERIAL_DATA;
-		ak->clk_mask = ICE1712_EWS88_SERIAL_CLOCK;
-		ak->cs_mask = ak->cs_addr = ICE1712_EWX2496_AK4524_CS;
-		ak->cs_none = 0;
-		ak->add_flags = ICE1712_EWS88_RW; /* set rw bit high */
-		ak->mask_flags = 0;
-		ak->ops.start = ewx2496_ak4524_start;
-		snd_ice1712_ak4524_init(ice);
+		snd_ice1712_akm4xxx_init(ak, &akm_ewx2496, ice);
 		break;
 	case ICE1712_SUBDEVICE_DMX6FIRE:
-		ak->num_adcs = ak->num_dacs = 6;
-		ak->type = SND_AK4524;
-		ak->caddr = 2;
-		ak->cif = 1; /* CIF high */
-		ak->data_mask = ICE1712_6FIRE_SERIAL_DATA;
-		ak->clk_mask = ICE1712_6FIRE_SERIAL_CLOCK;
-		ak->cs_mask = ak->cs_addr = 0; /* set later */
-		ak->cs_none = 0;
-		ak->add_flags = ICE1712_6FIRE_RW; /* set rw bit high */
-		ak->mask_flags = 0;
-		ak->ops.start = dmx6fire_ak4524_start;
-		snd_ice1712_ak4524_init(ice);
+		snd_ice1712_akm4xxx_init(ak, &akm_6fire, ice);
 		break;
 	}
 
@@ -472,11 +515,10 @@
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char mask = kcontrol->private_value & 0xff;
-	unsigned char saved[2];
 	
-	snd_ice1712_save_gpio_status(ice, saved);
+	snd_ice1712_save_gpio_status(ice);
 	ucontrol->value.enumerated.item[0] = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & mask ? 1 : 0;
-	snd_ice1712_restore_gpio_status(ice, saved);
+	snd_ice1712_restore_gpio_status(ice);
 	return 0;
 }
 
@@ -484,17 +526,16 @@
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char mask = kcontrol->private_value & 0xff;
-	unsigned char saved[2];
 	int val, nval;
 
 	if (kcontrol->private_value & (1 << 31))
 		return -EPERM;
 	nval = ucontrol->value.enumerated.item[0] ? mask : 0;
-	snd_ice1712_save_gpio_status(ice, saved);
+	snd_ice1712_save_gpio_status(ice);
 	val = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
 	nval |= val & ~mask;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, nval);
-	snd_ice1712_restore_gpio_status(ice, saved);
+	snd_ice1712_restore_gpio_status(ice);
 	return val != nval;
 }
 
@@ -864,8 +905,9 @@
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_EWX2496:
 	case ICE1712_SUBDEVICE_EWS88MT:
+	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_DMX6FIRE:
-		err = snd_ice1712_ak4524_build_controls(ice);
+		err = snd_ice1712_akm4xxx_build_controls(ice);
 		if (err < 0)
 			return err;
 		break;
@@ -881,6 +923,7 @@
 		}
 		break;
 	case ICE1712_SUBDEVICE_EWS88MT:
+	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 		for (idx = 0; idx < 8; idx++) {
 			kctl = snd_ctl_new1(&snd_ice1712_ews88mt_input_sense, ice);
 			kctl->id.index = idx;
@@ -915,25 +958,31 @@
 struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
 	{
 		ICE1712_SUBDEVICE_EWX2496,
-		"TerraTec EWX 24/96",
+		"TerraTec EWX24/96",
 		snd_ice1712_ews_init,
 		snd_ice1712_ews_add_controls,
 	},
 	{
 		ICE1712_SUBDEVICE_EWS88MT,
-		"TerraTec EWS 88MT",
+		"TerraTec EWS88MT",
+		snd_ice1712_ews_init,
+		snd_ice1712_ews_add_controls,
+	},
+	{
+		ICE1712_SUBDEVICE_EWS88MT_NEW,
+		"TerraTec EWS88MT",
 		snd_ice1712_ews_init,
 		snd_ice1712_ews_add_controls,
 	},
 	{
 		ICE1712_SUBDEVICE_EWS88D,
-		"TerraTec EWS 88D",
+		"TerraTec EWS88D",
 		snd_ice1712_ews_init,
 		snd_ice1712_ews_add_controls,
 	},
 	{
 		ICE1712_SUBDEVICE_DMX6FIRE,
-		"TerraTec DMX 6Fire",
+		"TerraTec DMX6Fire",
 		snd_ice1712_ews_init,
 		snd_ice1712_ews_add_controls,
 	},
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/ews.h linux-2.5.65-bk2/sound/pci/ice1712/ews.h
--- linux-2.5.65-bk1/sound/pci/ice1712/ews.h	Mon Mar 17 13:44:42 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/ews.h	Mon Mar 31 12:39:51 2003
@@ -33,6 +33,7 @@
 
 #define ICE1712_SUBDEVICE_EWX2496	0x3b153011
 #define ICE1712_SUBDEVICE_EWS88MT	0x3b151511
+#define ICE1712_SUBDEVICE_EWS88MT_NEW	0x3b152511
 #define ICE1712_SUBDEVICE_EWS88D	0x3b152b11
 #define ICE1712_SUBDEVICE_DMX6FIRE	0x3b153811
 
@@ -76,6 +77,6 @@
 #define ICE1712_6FIRE_RX2		0x80	/* MIDI2 */
 
 #define ICE1712_6FIRE_PCF9554_ADDR	(0x40>>1)
-#define ICE1712_6FIRE_CS8427_ADDR	(0x22>>1)
+#define ICE1712_6FIRE_CS8427_ADDR	(0x22)
 
 #endif /* __SOUND_EWS_H */
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/ice1712.c linux-2.5.65-bk2/sound/pci/ice1712/ice1712.c
--- linux-2.5.65-bk1/sound/pci/ice1712/ice1712.c	Mon Mar 17 13:44:02 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/ice1712.c	Mon Mar 31 12:39:51 2003
@@ -37,6 +37,10 @@
  *	Added support for VT1724 (Envy24HT)
  *	I have left out support for 176.4 and 192 KHz for the moment. 
  *  I also haven't done anything with the internal S/PDIF transmitter or the MPU-401
+ *
+ *  2003.02.20  Taksahi Iwai <tiwai@suse.de>
+ *	Split vt1724 part to an independent driver.
+ *	The GPIO is accessed through the callback functions now.
  */
 
 
@@ -57,13 +61,11 @@
 #include <sound/asoundef.h>
 
 #include "ice1712.h"
-#include "envy24ht.h"
 
 /* lowlevel routines */
 #include "delta.h"
 #include "ews.h"
 #include "hoontech.h"
-#include "amp.h"
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("ICEnsemble ICE1712 (Envy24)");
@@ -73,11 +75,8 @@
 	       HOONTECH_DEVICE_DESC
 	       DELTA_DEVICE_DESC
 	       EWS_DEVICE_DESC
-	       AMP_AUDIO2000_DEVICE_DESC
-		"{ICEnsemble,Generic ICE1712},"
-		"{ICEnsemble,Generic Envy24},"
-		"{ICEnsemble,Generic ICE1724},"
-		"{ICEnsemble,Generic Envy24HT}}");
+	       "{ICEnsemble,Generic ICE1712},"
+	       "{ICEnsemble,Generic Envy24}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
@@ -103,17 +102,9 @@
 #ifndef PCI_DEVICE_ID_ICE_1712
 #define PCI_DEVICE_ID_ICE_1712		0x1712
 #endif
-#ifndef PCI_DEVICE_ID_VT1724
-#define PCI_DEVICE_ID_VT1724		0x1724
-#endif
-
-enum {
-	TYPE_ICE1712, TYPE_VT1724
-};
 
 static struct pci_device_id snd_ice1712_ids[] __devinitdata = {
-	{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_ICE1712 },   /* ICE1712 */
-	{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_VT1724 },	   /* VT1724 */
+	{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },   /* ICE1712 */
 	{ 0, }
 };
 
@@ -130,6 +121,7 @@
  *  Basic I/O
  */
  
+/* check whether the clock mode is spdif-in */
 static inline int is_spdif_master(ice1712_t *ice)
 {
 	return (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER) ? 1 : 0;
@@ -257,6 +249,9 @@
 	return inw(ICEMT(ice, AC97_DATA));
 }
 
+/*
+ * consumer ac97 digital mix
+ */
 static int snd_ice1712_digmix_route_ac97_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -297,75 +292,27 @@
 };
 
 
-
 /*
- * set gpio direction, write mask and data
+ * gpio operations
  */
-void snd_ice1712_gpio_write_bits(ice1712_t *ice, int mask, int bits)
+static void snd_ice1712_set_gpio_dir(ice1712_t *ice, unsigned int data)
 {
-	ice->gpio_direction |= mask;
-	if (ice->vt1724) {
-
-		outw(ice->gpio_direction, ICEREG1724(ice, GPIO_DIRECTION));
-		outb((ice->gpio_direction&0xff0000)>>16, ICEREG1724(ice, GPIO_DIRECTION_22));
-
-		outw(~mask, ICEREG1724(ice, GPIO_WRITE_MASK));
-		outb((~mask & 0xff0000)>>16, ICEREG1724(ice, GPIO_WRITE_MASK_22));
-
-		outl(mask & bits, ICEREG1724(ice, GPIO_DATA));
-
-	}
-	else {
-		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio_direction);
-		snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~mask);
-		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, mask & bits);
-	}
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, data);
 }
 
-/*
- */
-/*
-	the VT1724 has 23 GPIO pins, so need 3 bytes for direction and 3 bytes for write mask
- */
-
-void snd_ice1712_save_gpio_status(ice1712_t *ice, unsigned char *tmp)
+static void snd_ice1712_set_gpio_mask(ice1712_t *ice, unsigned int data)
 {
-	down(&ice->gpio_mutex);
-	if (ice->vt1724) {
-		tmp[0] = ice->gpio_direction & 0xff;
-		tmp[1] = (ice->gpio_direction &0xff00)>>8;
-		tmp[2] = (ice->gpio_direction &0xff0000)>>16;
-
-		tmp[3] = ice->gpio_write_mask & 0xff;
-		tmp[4] = (ice->gpio_write_mask &0xff00)>>8;
-		tmp[5] = (ice->gpio_write_mask &0xff0000)>>16;
-	}
-	else {
-		tmp[0] = ice->gpio_direction;
-		tmp[1] = ice->gpio_write_mask;
-	}
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, data);
 }
 
-void snd_ice1712_restore_gpio_status(ice1712_t *ice, unsigned char *tmp)
+static unsigned int snd_ice1712_get_gpio_data(ice1712_t *ice)
 {
-	if (ice->vt1724) {
-
-		outw(tmp[0] | ((tmp[1]&0xff00)<<8), ICEREG1724(ice, GPIO_DIRECTION));
-		outb(tmp[2], ICEREG1724(ice, GPIO_DIRECTION_22));
-
-		outw(tmp[3] | ((tmp[4]&0xff00)<<8), ICEREG1724(ice, GPIO_WRITE_MASK));
-		outb(tmp[5], ICEREG1724(ice, GPIO_WRITE_MASK_22));
+	return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+}
 
-		ice->gpio_direction=tmp[0] | ((tmp[1]<<8)&0xff00) |((tmp[2]<<16)&0xff0000);
-		ice->gpio_write_mask=tmp[3] | ((tmp[4]<<8)&0xff00) |((tmp[5]<<16)&0xff0000);
-	}
-	else {
-		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, tmp[0]);
-		snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, tmp[1]);
-		ice->gpio_direction = tmp[0];
-		ice->gpio_write_mask = tmp[1];
-	}
-	up(&ice->gpio_mutex);
+static void snd_ice1712_set_gpio_data(ice1712_t *ice, unsigned int val)
+{
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, val);
 }
 
 
@@ -424,9 +371,9 @@
 	snd_cs8427_iec958_active(ice->cs8427, 0);
 }
 
-static void setup_cs8427(ice1712_t *ice, snd_pcm_substream_t * substream)
+static void setup_cs8427(ice1712_t *ice, int rate)
 {
-	snd_cs8427_iec958_pcm(ice->cs8427, substream->runtime->rate);
+	snd_cs8427_iec958_pcm(ice->cs8427, rate);
 }
 
 /*
@@ -442,7 +389,7 @@
 	}
 	ice->spdif.ops.open = open_cs8427;
 	ice->spdif.ops.close = close_cs8427;
-	ice->spdif.ops.setup = setup_cs8427;
+	ice->spdif.ops.setup_rate = setup_cs8427;
 	return 0;
 }
 
@@ -518,48 +465,6 @@
 }
 
 
-static void snd_vt1724_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	ice1712_t *ice = snd_magic_cast(ice1712_t, dev_id, return);
-	unsigned char status;
-
-	while (1) {
-		status = inb(ICEREG(ice, IRQSTAT));
-		if (status == 0)
-			break;
-		
-		/*  these should probably be separated at some point, 
-			but as we don't currently have MPU support on the board I will leave it */
-		if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) {
-			if (ice->rmidi[0])
-				snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs);
-			outb(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX, ICEREG(ice, IRQSTAT));
-			status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX);
-		}
-		if (status & VT1724_IRQ_MTPCM) {
-			unsigned char mtstat = inb(ICEMT(ice, IRQ));
-			if (mtstat & VT1724_MULTI_PDMA0) {
-				if (ice->playback_pro_substream)
-					snd_pcm_period_elapsed(ice->playback_pro_substream);
-				outb(VT1724_MULTI_PDMA0, ICEMT(ice, IRQ));
-			}
-			if (mtstat & VT1724_MULTI_RDMA0) {
-				if (ice->capture_pro_substream)
-					snd_pcm_period_elapsed(ice->capture_pro_substream);
-				outb(VT1724_MULTI_RDMA0, ICEMT(ice, IRQ));
-			}
-			/* ought to really handle this properly */
-			if (mtstat & VT1724_MULTI_FIFO_ERR) {
-				unsigned char fstat = inb(ICEMT1724(ice, DMA_FIFO_ERR));
-				outb(fstat, ICEMT1724(ice, DMA_FIFO_ERR));	
-				outb(VT1724_MULTI_FIFO_ERR | inb(ICEMT1724(ice, DMA_INT_MASK)), ICEMT1724(ice, DMA_INT_MASK));	
-				/* If I don't do this, I get machine lockup due to continual interrupts */
-			}
-
-		}
-	}
-}
-
 /*
  *  PCM part - misc
  */
@@ -1040,30 +945,16 @@
 		unsigned int old;
 		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 			return -EINVAL;
-		if (ice->vt1724) {
-			what = VT1724_PDMA0_PAUSE;
-			snd_pcm_trigger_done(substream, substream);
-			spin_lock(&ice->reg_lock);
-			old = inl(ICEMT1724(ice, DMA_PAUSE));
-			if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
-				old |= what;
-			else
-				old &= ~what;
-			outl(old, ICEMT1724(ice, DMA_PAUSE));
-			spin_unlock(&ice->reg_lock);
-		}
-		else {
-			what = ICE1712_PLAYBACK_PAUSE;
-			snd_pcm_trigger_done(substream, substream);
-			spin_lock(&ice->reg_lock);
-			old = inl(ICEMT(ice, PLAYBACK_CONTROL));
-			if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
-				old |= what;
-			else
-				old &= ~what;
-			outl(old, ICEMT(ice, PLAYBACK_CONTROL));
-			spin_unlock(&ice->reg_lock);
-		}
+		what = ICE1712_PLAYBACK_PAUSE;
+		snd_pcm_trigger_done(substream, substream);
+		spin_lock(&ice->reg_lock);
+		old = inl(ICEMT(ice, PLAYBACK_CONTROL));
+		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
+			old |= what;
+		else
+			old &= ~what;
+		outl(old, ICEMT(ice, PLAYBACK_CONTROL));
+		spin_unlock(&ice->reg_lock);
 		break;
 	}
 	case SNDRV_PCM_TRIGGER_START:
@@ -1078,10 +969,7 @@
 				what |= ICE1712_PLAYBACK_START;
 				snd_pcm_trigger_done(s, substream);
 			} else if (s == ice->capture_pro_substream) {
-				if (ice->vt1724)
-					what |= VT1724_RDMA0_START;
-				else
-					what |= ICE1712_CAPTURE_START_SHADOW;
+				what |= ICE1712_CAPTURE_START_SHADOW;
 				snd_pcm_trigger_done(s, substream);
 			}
 			s = s->link_next;
@@ -1108,17 +996,12 @@
 {
 	unsigned long flags;
 	unsigned char val;
+	unsigned int i;
 
 	spin_lock_irqsave(&ice->reg_lock, flags);
-	if (ice->vt1724 && 
-		((inb(ICEMT(ice, PLAYBACK_CONTROL)) & (VT1724_RDMA0_START|ICE1712_PLAYBACK_START)) || 
-		 (inb(ICEMT1724(ice, DMA_PAUSE) & VT1724_PDMA0_PAUSE)))) {
-		spin_unlock_irqrestore(&ice->reg_lock, flags);
-		return;
-	}
-	else if (!ice->vt1724 && (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
+	if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
 						 ICE1712_PLAYBACK_PAUSE|
-						 ICE1712_PLAYBACK_START))) {
+						 ICE1712_PLAYBACK_START)) {
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
 		return;
 	}
@@ -1150,8 +1033,10 @@
 
 	spin_unlock_irqrestore(&ice->reg_lock, flags);
 
-	if (ice->ak4524.ops.set_rate_val)
-		ice->ak4524.ops.set_rate_val(ice, rate);
+	for (i = 0; i < ice->akm_codecs; i++) {
+		if (ice->akm[i].ops.set_rate_val)
+			ice->akm[i].ops.set_rate_val(&ice->akm[i], rate);
+	}
 }
 
 static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream)
@@ -1159,47 +1044,31 @@
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 
 	ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream);
-	snd_ice1712_set_pro_rate(ice, substream->runtime->rate, 0);
 	spin_lock(&ice->reg_lock);
 	outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR));
-	if (ice->vt1724) {
-		outl((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE));	
-		outl((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT1724(ice, PLAYBACK_COUNT));
-
-		switch(substream->runtime->channels)
-		{
-			case 8:
-				outb(0, ICEMT1724(ice, BURST));
-				break;
-			case 6:
-				outb(1, ICEMT1724(ice, BURST));
-				break;
-			case 4:
-				outb(2, ICEMT1724(ice, BURST));
-				break;
-			case 2:
-				outb(3, ICEMT1724(ice, BURST));
-				break;
-		}
-	}
-	else {
-		outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE));
-		outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, PLAYBACK_COUNT));
-	}
+	outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE));
+	outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, PLAYBACK_COUNT));
 	spin_unlock(&ice->reg_lock);
 
-	if (ice->spdif.ops.setup)
-		ice->spdif.ops.setup(ice, substream);
-
 	return 0;
 }
 
+static int snd_ice1712_playback_pro_hw_params(snd_pcm_substream_t * substream,
+					      snd_pcm_hw_params_t * hw_params)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0);
+	if (ice->spdif.ops.setup_rate)
+		ice->spdif.ops.setup_rate(ice, params_rate(hw_params));
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
 static int snd_ice1712_capture_pro_prepare(snd_pcm_substream_t * substream)
 {
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 
 	ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream);
-	snd_ice1712_set_pro_rate(ice, substream->runtime->rate, 0);
 	spin_lock(&ice->reg_lock);
 	outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR));
 	outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE));
@@ -1208,6 +1077,15 @@
 	return 0;
 }
 
+static int snd_ice1712_capture_pro_hw_params(snd_pcm_substream_t * substream,
+					     snd_pcm_hw_params_t * hw_params)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0);
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
 static snd_pcm_uframes_t snd_ice1712_playback_pro_pointer(snd_pcm_substream_t * substream)
 {
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
@@ -1215,10 +1093,7 @@
 
 	if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START))
 		return 0;
-	if (ice->vt1724)
-		ptr = ice->playback_pro_size - ((inl(ICEMT(ice, PLAYBACK_SIZE))&0x7ffff) << 2);
-	else
-		ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2);
+	ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2);
 	return bytes_to_frames(substream->runtime, ptr);
 }
 
@@ -1253,27 +1128,6 @@
 	.fifo_size =		0,
 };
 
-static snd_pcm_hardware_t snd_vt1724_playback_pro =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
-	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
-	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000,
-	.rate_min =		4000,
-	.rate_max =		96000,
-	.channels_min =		2,
-	.channels_max =		8,
-	.buffer_bytes_max =	0x7ffff0,	/* we have 18bits for the buffer size, in dwords */
-	.period_bytes_min =	8 * 4 * 2,
-	.period_bytes_max =	131040,		/* do we have 18bits for terminal count? 
-										Datasheets says bits 18:0 but only has 2 byte registers (1C-1Dh ) */
-	.periods_min =		1,
-	.periods_max =		1024,
-	.fifo_size =		0,
-};
-
 static snd_pcm_hardware_t snd_ice1712_capture_pro =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
@@ -1294,36 +1148,13 @@
 	.fifo_size =		0,
 };
 
-static snd_pcm_hardware_t snd_ice1724_capture_pro =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
-	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
-	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000,
-	.rate_min =		4000,
-	.rate_max =		96000,
-	.channels_min =		2,
-	.channels_max =		2,
-	.buffer_bytes_max =	(256*1024),
-	.period_bytes_min =	2 * 4 * 2,
-	.period_bytes_max =	131040,
-	.periods_min =		1,
-	.periods_max =		1024,
-	.fifo_size =		0,
-};
-
 static int snd_ice1712_playback_pro_open(snd_pcm_substream_t * substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 
 	ice->playback_pro_substream = substream;
-	if (ice->vt1724)
-		runtime->hw = snd_vt1724_playback_pro;
-	else
-		runtime->hw = snd_ice1712_playback_pro;
+	runtime->hw = snd_ice1712_playback_pro;
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
@@ -1340,10 +1171,7 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	ice->capture_pro_substream = substream;
-	if (ice->vt1724)
-		runtime->hw = snd_ice1724_capture_pro;
-	else
-		runtime->hw = snd_ice1712_capture_pro;
+	runtime->hw = snd_ice1712_capture_pro;
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
@@ -1384,7 +1212,7 @@
 	.open =		snd_ice1712_playback_pro_open,
 	.close =	snd_ice1712_playback_pro_close,
 	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_ice1712_hw_params,
+	.hw_params =	snd_ice1712_playback_pro_hw_params,
 	.hw_free =	snd_ice1712_hw_free,
 	.prepare =	snd_ice1712_playback_pro_prepare,
 	.trigger =	snd_ice1712_pro_trigger,
@@ -1395,7 +1223,7 @@
 	.open =		snd_ice1712_capture_pro_open,
 	.close =	snd_ice1712_capture_pro_close,
 	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_ice1712_hw_params,
+	.hw_params =	snd_ice1712_capture_pro_hw_params,
 	.hw_free =	snd_ice1712_hw_free,
 	.prepare =	snd_ice1712_capture_pro_prepare,
 	.trigger =	snd_ice1712_pro_trigger,
@@ -1613,7 +1441,7 @@
 {
 	int err;
 
-	if (!(ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97)) {
+	if (ice_has_con_ac97(ice)) {
 		ac97_t ac97;
 		memset(&ac97, 0, sizeof(ac97));
 		ac97.write = snd_ice1712_ac97_write;
@@ -1628,8 +1456,8 @@
 			return 0;
 		}
 	}
-	/* hmm.. can we have both consumer and pro ac97 mixers? */
-	if (! (ice->eeprom.aclink & ICE1712_CFG_PRO_I2S)) {
+
+	if (! (ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
 		ac97_t ac97;
 		memset(&ac97, 0, sizeof(ac97));
 		ac97.write = snd_ice1712_pro_ac97_write;
@@ -1650,47 +1478,46 @@
  *
  */
 
+static inline unsigned int eeprom_double(ice1712_t *ice, int idx)
+{
+	return (unsigned int)ice->eeprom.data[idx] | ((unsigned int)ice->eeprom.data[idx + 1] << 8);
+}
+
 static void snd_ice1712_proc_read(snd_info_entry_t *entry, 
 				  snd_info_buffer_t * buffer)
 {
 	ice1712_t *ice = snd_magic_cast(ice1712_t, entry->private_data, return);
 	unsigned int idx;
 
-	snd_iprintf(buffer, "ICE1712\n\n");
+	snd_iprintf(buffer, "%s\n\n", ice->card->longname);
 	snd_iprintf(buffer, "EEPROM:\n");
+
 	snd_iprintf(buffer, "  Subvendor        : 0x%x\n", ice->eeprom.subvendor);
 	snd_iprintf(buffer, "  Size             : %i bytes\n", ice->eeprom.size);
 	snd_iprintf(buffer, "  Version          : %i\n", ice->eeprom.version);
-	snd_iprintf(buffer, "  Codec            : 0x%x\n", ice->eeprom.codec);
-	snd_iprintf(buffer, "  ACLink           : 0x%x\n", ice->eeprom.aclink);
-	snd_iprintf(buffer, "  I2S ID           : 0x%x\n", ice->eeprom.i2sID);
-	snd_iprintf(buffer, "  S/PDIF           : 0x%x\n", ice->eeprom.spdif);
+	snd_iprintf(buffer, "  Codec            : 0x%x\n", ice->eeprom.data[ICE_EEP1_CODEC]);
+	snd_iprintf(buffer, "  ACLink           : 0x%x\n", ice->eeprom.data[ICE_EEP1_ACLINK]);
+	snd_iprintf(buffer, "  I2S ID           : 0x%x\n", ice->eeprom.data[ICE_EEP1_I2SID]);
+	snd_iprintf(buffer, "  S/PDIF           : 0x%x\n", ice->eeprom.data[ICE_EEP1_SPDIF]);
 	snd_iprintf(buffer, "  GPIO mask        : 0x%x\n", ice->eeprom.gpiomask);
 	snd_iprintf(buffer, "  GPIO state       : 0x%x\n", ice->eeprom.gpiostate);
 	snd_iprintf(buffer, "  GPIO direction   : 0x%x\n", ice->eeprom.gpiodir);
-	snd_iprintf(buffer, "  AC'97 main       : 0x%x\n", ice->eeprom.ac97main);
-	snd_iprintf(buffer, "  AC'97 pcm        : 0x%x\n", ice->eeprom.ac97pcm);
-	snd_iprintf(buffer, "  AC'97 record     : 0x%x\n", ice->eeprom.ac97rec);
-	snd_iprintf(buffer, "  AC'97 record src : 0x%x\n", ice->eeprom.ac97recsrc);
+	snd_iprintf(buffer, "  AC'97 main       : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_MAIN_LO));
+	snd_iprintf(buffer, "  AC'97 pcm        : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_PCM_LO));
+	snd_iprintf(buffer, "  AC'97 record     : 0x%x\n", eeprom_double(ice, ICE_EEP1_AC97_REC_LO));
+	snd_iprintf(buffer, "  AC'97 record src : 0x%x\n", ice->eeprom.data[ICE_EEP1_AC97_RECSRC]);
 	for (idx = 0; idx < 4; idx++)
-		snd_iprintf(buffer, "  DAC ID #%i        : 0x%x\n", idx, ice->eeprom.dacID[idx]);
+		snd_iprintf(buffer, "  DAC ID #%i        : 0x%x\n", idx, ice->eeprom.data[ICE_EEP1_DAC_ID + idx]);
 	for (idx = 0; idx < 4; idx++)
-		snd_iprintf(buffer, "  ADC ID #%i        : 0x%x\n", idx, ice->eeprom.adcID[idx]);
-	for (idx = 0x1c; idx < ice->eeprom.size && idx < 0x1c + sizeof(ice->eeprom.extra); idx++)
-		snd_iprintf(buffer, "  Extra #%02i        : 0x%x\n", idx, ice->eeprom.extra[idx - 0x1c]);
+		snd_iprintf(buffer, "  ADC ID #%i        : 0x%x\n", idx, ice->eeprom.data[ICE_EEP1_ADC_ID + idx]);
+	for (idx = 0x1c; idx < ice->eeprom.size; idx++)
+		snd_iprintf(buffer, "  Extra #%02i        : 0x%x\n", idx, ice->eeprom.data[idx]);
+
 	snd_iprintf(buffer, "\nRegisters:\n");
-	if (ice->vt1724) {
-		snd_iprintf(buffer, "  PSDOUT03         : 0x%08x\n", (unsigned)inl(ICEMT1724(ice, ROUTE_PLAYBACK)));
-		for (idx = 0x0; idx < 0x20 ; idx++)
-			snd_iprintf(buffer, "  CCS%02x         : 0x%02x\n", idx, inb(ice->port+idx));
-		for (idx = 0x0; idx < 0x30 ; idx++)
-			snd_iprintf(buffer, "  MT%02x         : 0x%02x\n", idx, inb(ice->profi_port+idx));
-	} else {
-		snd_iprintf(buffer, "  PSDOUT03         : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_PSDOUT03)));
-		snd_iprintf(buffer, "  CAPTURE          : 0x%08x\n", inl(ICEMT(ice, ROUTE_CAPTURE)));
-		snd_iprintf(buffer, "  SPDOUT           : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_SPDOUT)));
-		snd_iprintf(buffer, "  RATE             : 0x%02x\n", (unsigned)inb(ICEMT(ice, RATE)));
-	}
+	snd_iprintf(buffer, "  PSDOUT03         : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_PSDOUT03)));
+	snd_iprintf(buffer, "  CAPTURE          : 0x%08x\n", inl(ICEMT(ice, ROUTE_CAPTURE)));
+	snd_iprintf(buffer, "  SPDOUT           : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_SPDOUT)));
+	snd_iprintf(buffer, "  RATE             : 0x%02x\n", (unsigned)inb(ICEMT(ice, RATE)));
 }
 
 static void __devinit snd_ice1712_proc_init(ice1712_t * ice)
@@ -1708,7 +1535,7 @@
 static int snd_ice1712_eeprom_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
-	uinfo->count = 32;
+	uinfo->count = sizeof(ice1712_eeprom_t);
 	return 0;
 }
 
@@ -1716,7 +1543,7 @@
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	
-	memcpy(ucontrol->value.bytes.data, &ice->eeprom, 32);
+	memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom));
 	return 0;
 }
 
@@ -1866,14 +1693,10 @@
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char mask = kcontrol->private_value & 0xff;
 	int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0;
-	unsigned char saved[6];
 	
-	snd_ice1712_save_gpio_status(ice, saved);
-	if (ice->vt1724)
-		ucontrol->value.integer.value[0] = (inb(ICEREG1724(ice, GPIO_DATA)) & mask ? 1 : 0) ^ invert;
-	else
-		ucontrol->value.integer.value[0] = (snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & mask ? 1 : 0) ^ invert;
-	snd_ice1712_restore_gpio_status(ice, saved);
+	snd_ice1712_save_gpio_status(ice);
+	ucontrol->value.integer.value[0] = (snd_ice1712_gpio_read(ice) & mask ? 1 : 0) ^ invert;
+	snd_ice1712_restore_gpio_status(ice);
 	return 0;
 }
 
@@ -1882,24 +1705,17 @@
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	unsigned char mask = kcontrol->private_value & 0xff;
 	int invert = (kcontrol->private_value & (1<<24)) ? mask : 0;
-	unsigned char saved[6];
-	int val, nval;
+	unsigned int val, nval;
 
 	if (kcontrol->private_value & (1 << 31))
 		return -EPERM;
 	nval = (ucontrol->value.integer.value[0] ? mask : 0) ^ invert;
-	snd_ice1712_save_gpio_status(ice, saved);
-	if (ice->vt1724) {
-		val = inb(ICEREG1724(ice, GPIO_DATA));
-		nval |= val & ~mask;
-		outb(nval, ICEREG1724(ice, GPIO_DATA));
-	}
-	else {
-		val = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
-		nval |= val & ~mask;
-		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, nval);
-	}
-	snd_ice1712_restore_gpio_status(ice, saved);
+	snd_ice1712_save_gpio_status(ice);
+	val = snd_ice1712_gpio_read(ice);
+	nval |= val & ~mask;
+	if (val != nval)
+		snd_ice1712_gpio_write(ice, nval);
+	snd_ice1712_restore_gpio_status(ice);
 	return val != nval;
 }
 
@@ -1985,14 +1801,19 @@
 			snd_ice1712_cs8427_set_input_clock(ice, is_spdif_master(ice));
 		}
 		/* notify ak4524 chip as well */
-		if (is_spdif_master(ice) && ice->ak4524.ops.set_rate_val)
-			ice->ak4524.ops.set_rate_val(ice, 0);
+		if (is_spdif_master(ice)) {
+			unsigned int i;
+			for (i = 0; i < ice->akm_codecs; i++) {
+				if (ice->akm[i].ops.set_rate_val)
+					ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
+			}
+		}
 	}
 
 	return change;
 }
 
-static snd_kcontrol_new_t snd_ice1712_pro_internal_clock = __devinitdata {
+static snd_kcontrol_new_t snd_ice1712_pro_internal_clock __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Internal Clock",
 	.info = snd_ice1712_pro_internal_clock_info,
@@ -2011,16 +1832,20 @@
 
 static int snd_ice1712_pro_rate_locking_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
-	ucontrol->value.integer.value[0] = PRO_RATE_LOCKED ? 1 : 0;
+	ucontrol->value.integer.value[0] = PRO_RATE_LOCKED;
 	return 0;
 }
 
 static int snd_ice1712_pro_rate_locking_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
-	int change = 0;
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int change = 0, nval;
 
-	change = PRO_RATE_LOCKED ? 1 : 0 != ucontrol->value.integer.value[0] ? 1 : 0;
-	PRO_RATE_LOCKED = ucontrol->value.integer.value[0] ? 1 : 0;
+	nval = ucontrol->value.integer.value[0] ? 1 : 0;
+	spin_lock_irq(&ice->reg_lock);
+	change = PRO_RATE_LOCKED != nval;
+	PRO_RATE_LOCKED = nval;
+	spin_unlock_irq(&ice->reg_lock);
 	return change;
 }
 
@@ -2043,16 +1868,20 @@
 
 static int snd_ice1712_pro_rate_reset_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
-	ucontrol->value.integer.value[0] = PRO_RATE_RESET ? 1 : 0;
+	ucontrol->value.integer.value[0] = PRO_RATE_RESET;
 	return 0;
 }
 
 static int snd_ice1712_pro_rate_reset_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
-	int change = 0;
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int change = 0, nval;
 
-	change = PRO_RATE_LOCKED ? 1 : 0 != ucontrol->value.integer.value[0] ? 1 : 0;
-	PRO_RATE_RESET = ucontrol->value.integer.value[0] ? 1 : 0;
+	nval = ucontrol->value.integer.value[0] ? 1 : 0;
+	spin_lock_irq(&ice->reg_lock);
+	change = PRO_RATE_RESET != nval;
+	PRO_RATE_RESET = nval;
+	spin_unlock_irq(&ice->reg_lock);
 	return change;
 }
 
@@ -2234,141 +2063,6 @@
 };
 
 
-static int snd_vt1724_pro_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	static char *texts[] = {
-		"PCM Out", /* 0 */
-		"H/W In 0", "H/W In 1", /* 1-2 */
-		"IEC958 In L", "IEC958 In R", /* 3-4 */
-	};
-	
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 5;//kcontrol->id.index < 2 ? 12 : 11;
-	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_vt1724_pro_route_analog_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx = kcontrol->id.index;
-	unsigned long val;
-	unsigned char eitem;
-	static unsigned char xlate[8] = {
-		0, 255, 1, 2, 255, 255, 3, 4,
-	};
-
-	val = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
-	val >>= ((idx % 2) * 12) + ((idx / 2) * 3)+8;
-	val &= 7;	//we now have 3 bits per output
-	eitem=xlate[val];
-	if (eitem == 255) {
-		snd_BUG();
-		eitem = 0;
-	}
-	ucontrol->value.enumerated.item[0] = eitem;
-
-	return 0;
-}
-
-static int snd_vt1724_pro_route_analog_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int change, shift;
-	int idx = kcontrol->id.index;
-	unsigned int val, old_val, nval;
-	static unsigned char xroute[8] = {
-		0, /* PCM */
-		2, /* PSDIN0 Left */
-		3, /* PSDIN0 Right */
-		6, /* SPDIN Left */
-		7,  /* SPDIN Right */
-	};
-	
-	/* update PSDOUT */
-
-	nval=xroute[ucontrol->value.enumerated.item[0]&7];
-	shift = ((idx % 2) * 12) + ((idx / 2) * 3) +8;
-	val = old_val = inw(ICEMT1724(ice, ROUTE_PLAYBACK));
-	val &= ~(0x07 << shift);
-	val |= nval << shift;
-	change = val != old_val;
-	if (change)
-		outw(val, ICEMT1724(ice, ROUTE_PLAYBACK));
-	return change;
-}
-
-static int snd_vt1724_pro_route_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx = kcontrol->id.index;
-	unsigned long val;
-	unsigned char eitem;
-	static unsigned char xlate[8] = {
-		0, 255, 1, 2, 255, 255, 3, 4,
-	};
-
-	val = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
-	val >>= idx*3;	//I hope this is right
-	val &= 7;	
-
-	eitem=xlate[val];
-	if (eitem == 255) {
-		snd_BUG();
-		eitem = 0;
-	}
-	ucontrol->value.enumerated.item[0] = eitem;
-	return 0;
-}
-
-static int snd_vt1724_pro_route_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int change, shift;
-	int idx = kcontrol->id.index;
-	unsigned long val, old_val, nval;
-	static unsigned char xroute[8] = {
-		0, /* PCM */
-		2, /* PSDIN0 Left */
-		3, /* PSDIN0 Right */
-		6, /* SPDIN Left */
-		7,  /* SPDIN Right */
-	};
-	
-	/* update SPDOUT */
-	val = old_val = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
-	nval = xroute[ucontrol->value.enumerated.item[0]&7];
-
-	shift = idx * 2;
-	val &= ~(0x07 << shift);
-	val |= nval << shift;
-	shift = idx * 4 + 8;
-	change = val != old_val;
-	if (change)
-		outl(val, ICEMT1724(ice, ROUTE_PLAYBACK));
-	return change;
-}
-
-static snd_kcontrol_new_t snd_vt1724_mixer_pro_analog_route __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "H/W Playback Route",
-	.info = snd_vt1724_pro_route_info,
-	.get = snd_vt1724_pro_route_analog_get,
-	.put = snd_vt1724_pro_route_analog_put,
-};
-
-static snd_kcontrol_new_t snd_vt1724_mixer_pro_spdif_route __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "IEC958 Playback Route",
-	.info = snd_vt1724_pro_route_info,
-	.get = snd_vt1724_pro_route_spdif_get,
-	.put = snd_vt1724_pro_route_spdif_put,
-};
-
-
 static int snd_ice1712_pro_volume_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -2456,7 +2150,7 @@
 static int __devinit snd_ice1712_read_eeprom(ice1712_t *ice)
 {
 	int dev = 0xa0;		/* EEPROM device address */
-	unsigned int idx;
+	unsigned int i;
 
 	if ((inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_EEPROM) == 0) {
 		snd_printk("ICE1712 has not detected EEPROM\n");
@@ -2467,39 +2161,22 @@
 				(snd_ice1712_read_i2c(ice, dev, 0x02) << 16) | 
 				(snd_ice1712_read_i2c(ice, dev, 0x03) << 24);
 	ice->eeprom.size = snd_ice1712_read_i2c(ice, dev, 0x04);
-	if (ice->eeprom.size < 28) {
+	if (ice->eeprom.size > 32) {
 		snd_printk("invalid EEPROM (size = %i)\n", ice->eeprom.size);
 		return -EIO;
 	}
 	ice->eeprom.version = snd_ice1712_read_i2c(ice, dev, 0x05);
 	if (ice->eeprom.version != 1) {
 		snd_printk("invalid EEPROM version %i\n", ice->eeprom.version);
-		return -EIO;
-	}
-	ice->eeprom.codec = snd_ice1712_read_i2c(ice, dev, 0x06);
-	if (ice->vt1724)
-		ice->eeprom.codec |= ICE1712_CFG_NO_CON_AC97;	/* little hack here */
-	ice->eeprom.aclink = snd_ice1712_read_i2c(ice, dev, 0x07);
-	ice->eeprom.i2sID = snd_ice1712_read_i2c(ice, dev, 0x08);
-	ice->eeprom.spdif = snd_ice1712_read_i2c(ice, dev, 0x09);
-	if (ice->vt1724)
-		ice->eeprom.spdif &= ~VT1724_CFG_SPDIF_OUT_EN;	/* little hack here */
-	ice->eeprom.gpiomask = snd_ice1712_read_i2c(ice, dev, 0x0a);
-	ice->eeprom.gpiostate = snd_ice1712_read_i2c(ice, dev, 0x0b);
-	ice->eeprom.gpiodir = snd_ice1712_read_i2c(ice, dev, 0x0c);
-	ice->eeprom.ac97main = (snd_ice1712_read_i2c(ice, dev, 0x0d) << 0) |
-			       (snd_ice1712_read_i2c(ice, dev, 0x0e) << 8);
-	ice->eeprom.ac97pcm = (snd_ice1712_read_i2c(ice, dev, 0x0f) << 0) |
-			      (snd_ice1712_read_i2c(ice, dev, 0x10) << 8);
-	ice->eeprom.ac97rec = (snd_ice1712_read_i2c(ice, dev, 0x11) << 0) |
-			      (snd_ice1712_read_i2c(ice, dev, 0x12) << 8);
-	ice->eeprom.ac97recsrc = snd_ice1712_read_i2c(ice, dev, 0x13) << 0;
-	for (idx = 0; idx < 4; idx++) {
-		ice->eeprom.dacID[idx] = snd_ice1712_read_i2c(ice, dev, 0x14 + idx);
-		ice->eeprom.adcID[idx] = snd_ice1712_read_i2c(ice, dev, 0x18 + idx);
+		/* return -EIO; */
 	}
-	for (idx = 0x1c; idx < ice->eeprom.size && idx < 0x1c + sizeof(ice->eeprom.extra); idx++)
-		ice->eeprom.extra[idx - 0x1c] = snd_ice1712_read_i2c(ice, dev, idx);
+	for (i = 0; i < ice->eeprom.size; i++)
+		ice->eeprom.data[i] = snd_ice1712_read_i2c(ice, dev, i + 6);
+
+	ice->eeprom.gpiomask = ice->eeprom.data[ICE_EEP1_GPIO_MASK];
+	ice->eeprom.gpiostate = ice->eeprom.data[ICE_EEP1_GPIO_STATE];
+	ice->eeprom.gpiodir = ice->eeprom.data[ICE_EEP1_GPIO_DIR];
+
 	return 0;
 }
 
@@ -2511,25 +2188,25 @@
 	udelay(200);
 	outb(ICE1712_NATIVE, ICEREG(ice, CONTROL));
 	udelay(200);
-	pci_write_config_byte(ice->pci, 0x60, ice->eeprom.codec);
-	pci_write_config_byte(ice->pci, 0x61, ice->eeprom.aclink);
-	pci_write_config_byte(ice->pci, 0x62, ice->eeprom.i2sID);
-	pci_write_config_byte(ice->pci, 0x63, ice->eeprom.spdif);
+	pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
+	pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]);
+	pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]);
+	pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]);
 	if (ice->eeprom.subvendor != ICE1712_SUBDEVICE_STDSP24) {
-		ice->gpio_write_mask = ice->eeprom.gpiomask;
-		ice->gpio_direction = ice->eeprom.gpiodir;
+		ice->gpio.write_mask = ice->eeprom.gpiomask;
+		ice->gpio.direction = ice->eeprom.gpiodir;
 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ice->eeprom.gpiomask);
 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->eeprom.gpiodir);
 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ice->eeprom.gpiostate);
 	} else {
-		ice->gpio_write_mask = 0xc0;
-		ice->gpio_direction = 0xff;
+		ice->gpio.write_mask = 0xc0;
+		ice->gpio.direction = 0xff;
 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, 0xc0);
 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 0xff);
 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ICE1712_STDSP24_CLOCK_BIT);
 	}
 	snd_ice1712_write(ice, ICE1712_IREG_PRO_POWERDOWN, 0);
-	if (!(ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97)) {
+	if (!(ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97)) {
 		outb(ICE1712_AC97_WARM, ICEREG(ice, AC97_CMD));
 		udelay(100);
 		outb(0, ICEREG(ice, AC97_CMD));
@@ -2540,28 +2217,6 @@
 	return 0;
 }
 
-static int __devinit snd_vt1724_chip_init(ice1712_t *ice)
-{
-	outb(VT1724_RESET , ICEREG(ice, CONTROL));
-	udelay(200);
-	outb(0, ICEREG(ice, CONTROL));
-	udelay(200);
-	outb(ice->eeprom.codec, ICEREG1724(ice, SYS_CFG));
-	outb(ice->eeprom.aclink&0x7f, ICEREG1724(ice, AC97_CFG));
-	outb(ice->eeprom.i2sID, ICEREG1724(ice, I2S_FEATURES));
-	outb(ice->eeprom.spdif, ICEREG1724(ice, SPDIF_CFG));
-
-	ice->gpio_write_mask = ice->eeprom.gpiomask;
-	ice->gpio_direction = ice->eeprom.gpiodir;
-	outb(ice->eeprom.gpiomask, ICEREG1724(ice, GPIO_WRITE_MASK));
-	outb(ice->eeprom.gpiodir, ICEREG1724(ice, GPIO_DIRECTION));
-	outb(ice->eeprom.gpiostate, ICEREG1724(ice, GPIO_DATA));
-
-	outb(0, ICEREG1724(ice, POWERDOWN));	
-
-	return 0;
-}
-
 int __devinit snd_ice1712_spdif_build_controls(ice1712_t *ice)
 {
 	int err;
@@ -2602,63 +2257,40 @@
 	if (err < 0)
 		return err;
 
-	if (ice->vt1724) {
-		for (idx = 0; idx < ice->num_total_dacs; idx++) {
-			kctl = snd_ctl_new1(&snd_vt1724_mixer_pro_analog_route, ice);
-			if (kctl == NULL)
-				return -ENOMEM;
-			kctl->id.index = idx;
-			err = snd_ctl_add(ice->card, kctl);
-			if (err < 0)
-				return err;
-		}
-		for (idx = 0; idx < 2; idx++) {
-			kctl = snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice);
-			if (kctl == NULL)
-				return -ENOMEM;
-			kctl->id.index = idx;
-			err = snd_ctl_add(ice->card, kctl);
-			if (err < 0)
-				return err;
-		}
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
-		if (err < 0)
-			return err;
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_locking, ice));
+	if (err < 0)
+		return err;
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_reset, ice));
+	if (err < 0)
+		return err;
 
-	}
-	else {
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_locking, ice));
-		if (err < 0)
-			return err;
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_reset, ice));
+	for (idx = 0; idx < ice->num_total_dacs; idx++) {
+		kctl = snd_ctl_new1(&snd_ice1712_mixer_pro_analog_route, ice);
+		if (kctl == NULL)
+			return -ENOMEM;
+		kctl->id.index = idx;
+		err = snd_ctl_add(ice->card, kctl);
 		if (err < 0)
 			return err;
+	}
 
-		for (idx = 0; idx < ice->num_total_dacs; idx++) {
-			kctl = snd_ctl_new1(&snd_ice1712_mixer_pro_analog_route, ice);
-			if (kctl == NULL)
-				return -ENOMEM;
-			kctl->id.index = idx;
-			err = snd_ctl_add(ice->card, kctl);
-			if (err < 0)
-				return err;
-		}
-		for (idx = 0; idx < 2; idx++) {
-			kctl = snd_ctl_new1(&snd_ice1712_mixer_pro_spdif_route, ice);
-			if (kctl == NULL)
-				return -ENOMEM;
-			kctl->id.index = idx;
-			err = snd_ctl_add(ice->card, kctl);
-			if (err < 0)
-				return err;
-		}
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice));
-		if (err < 0)
-			return err;
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
+	for (idx = 0; idx < 2; idx++) {
+		kctl = snd_ctl_new1(&snd_ice1712_mixer_pro_spdif_route, ice);
+		if (kctl == NULL)
+			return -ENOMEM;
+		kctl->id.index = idx;
+		err = snd_ctl_add(ice->card, kctl);
 		if (err < 0)
 			return err;
 	}
+
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice));
+	if (err < 0)
+		return err;
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
+	if (err < 0)
+		return err;
+
 	return 0;
 }
 
@@ -2667,10 +2299,7 @@
 	if (ice->res_port == NULL)
 		goto __hw_end;
 	/* mask all interrupts */
-	if (ice->vt1724)
-		outb(0xff, ICEMT1724(ice, DMA_INT_MASK));
-	else
-		outb(0xc0, ICEMT(ice, IRQ));
+	outb(0xc0, ICEMT(ice, IRQ));
 	outb(0xff, ICEREG(ice, IRQMASK));
 	/* --- */
       __hw_end:
@@ -2694,6 +2323,8 @@
 		release_resource(ice->res_profi_port);
 		kfree_nocheck(ice->res_profi_port);
 	}
+	if (ice->akm)
+		kfree(ice->akm);
 	snd_magic_kfree(ice);
 	return 0;
 }
@@ -2706,7 +2337,6 @@
 
 static int __devinit snd_ice1712_create(snd_card_t * card,
 					struct pci_dev *pci,
-					int vt1724,
 					int omni,
 					ice1712_t ** r_ice1712)
 {
@@ -2721,25 +2351,24 @@
         /* enable PCI device */
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
-	/* VT1724 does not have 28bit DMA transfer limit */
-	if (! vt1724) {
-		/* check, if we can restrict PCI DMA transfers to 28 bits */
-		if (!pci_dma_supported(pci, 0x0fffffff)) {
-			snd_printk("architecture does not support 28bit PCI busmaster DMA\n");
-			return -ENXIO;
-		}
-		pci_set_dma_mask(pci, 0x0fffffff);
+	/* check, if we can restrict PCI DMA transfers to 28 bits */
+	if (!pci_dma_supported(pci, 0x0fffffff)) {
+		snd_printk("architecture does not support 28bit PCI busmaster DMA\n");
+		return -ENXIO;
 	}
-	else
-		pci_set_dma_mask(pci, 0xffffffff); 
+	pci_set_dma_mask(pci, 0x0fffffff);
 
 	ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL);
 	if (ice == NULL)
 		return -ENOMEM;
-	ice->vt1724 = vt1724 ? 1 : 0;
 	ice->omni = omni ? 1 : 0;
 	spin_lock_init(&ice->reg_lock);
 	init_MUTEX(&ice->gpio_mutex);
+	ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
+	ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
+	ice->gpio.set_data = snd_ice1712_set_gpio_data;
+	ice->gpio.get_data = snd_ice1712_get_gpio_data;
+
 	ice->spdif.cs8403_bits =
 		ice->spdif.cs8403_stream_bits = (0x01 |	/* consumer format */
 						 0x10 |	/* no emphasis */
@@ -2748,101 +2377,57 @@
 	ice->pci = pci;
 	ice->irq = -1;
 	ice->port = pci_resource_start(pci, 0);
-	if (ice->vt1724) {
-		ice->profi_port = pci_resource_start(pci, 1);
-		pci_set_master(pci);
-		snd_ice1712_proc_init(ice);
-		synchronize_irq(pci->irq);
-
-		if ((ice->res_port = request_region(ice->port, 32, "ICE1724 - Controller")) == NULL) {
-			snd_ice1712_free(ice);
-			snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->port, ice->port + 32 - 1);
-			return -EIO;
-		}
+	ice->ddma_port = pci_resource_start(pci, 1);
+	ice->dmapath_port = pci_resource_start(pci, 2);
+	ice->profi_port = pci_resource_start(pci, 3);
+	pci_set_master(pci);
+	pci_write_config_word(ice->pci, 0x40, 0x807f);
+	pci_write_config_word(ice->pci, 0x42, 0x0006);
+	snd_ice1712_proc_init(ice);
+	synchronize_irq(pci->irq);
 
-		if ((ice->res_profi_port = request_region(ice->profi_port, 128, "ICE1724 - Professional")) == NULL) {
-			snd_ice1712_free(ice);
-			snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->profi_port, ice->profi_port + 16 - 1);
-			return -EIO;
-		}
-		
-		if (request_irq(pci->irq, snd_vt1724_interrupt, SA_INTERRUPT|SA_SHIRQ, "ICE1724", (void *) ice)) {
-			snd_ice1712_free(ice);
-			snd_printk("unable to grab IRQ %d\n", pci->irq);
-			return -EIO;
-		}
-
-		ice->irq = pci->irq;
-
-		if (snd_ice1712_read_eeprom(ice) < 0) {
-			snd_ice1712_free(ice);
-			return -EIO;
-		}
-		if (snd_vt1724_chip_init(ice) < 0) {
-			snd_ice1712_free(ice);
-			return -EIO;
-		}
-
-		/* unmask used interrupts */
-		outb((ice->eeprom.codec & ICE1712_CFG_2xMPU401) == 0 ? (VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX) : 0 ,
-			 ICEREG(ice, IRQMASK));
-		/* don't handle FIFO overrun/underruns (just yet), since they cause machine lockups */
-		outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK));	
-	}
-	else {
-		ice->ddma_port = pci_resource_start(pci, 1);
-		ice->dmapath_port = pci_resource_start(pci, 2);
-		ice->profi_port = pci_resource_start(pci, 3);
-		pci_set_master(pci);
-		pci_write_config_word(ice->pci, 0x40, 0x807f);
-		pci_write_config_word(ice->pci, 0x42, 0x0006);
-		snd_ice1712_proc_init(ice);
-		synchronize_irq(pci->irq);
-	
-
-		if ((ice->res_port = request_region(ice->port, 32, "ICE1712 - Controller")) == NULL) {
-			snd_ice1712_free(ice);
-			snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->port, ice->port + 32 - 1);
-			return -EIO;
-		}
-		if ((ice->res_ddma_port = request_region(ice->ddma_port, 16, "ICE1712 - DDMA")) == NULL) {
-			snd_ice1712_free(ice);
-			snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->ddma_port, ice->ddma_port + 16 - 1);
-			return -EIO;
-		}
-		if ((ice->res_dmapath_port = request_region(ice->dmapath_port, 16, "ICE1712 - DMA path")) == NULL) {
-			snd_ice1712_free(ice);
-			snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->dmapath_port, ice->dmapath_port + 16 - 1);
-			return -EIO;
-		}
-		if ((ice->res_profi_port = request_region(ice->profi_port, 64, "ICE1712 - Professional")) == NULL) {
-			snd_ice1712_free(ice);
-			snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->profi_port, ice->profi_port + 16 - 1);
-			return -EIO;
-		}
-		if (request_irq(pci->irq, snd_ice1712_interrupt, SA_INTERRUPT|SA_SHIRQ, "ICE1712", (void *) ice)) {
-			snd_ice1712_free(ice);
-			snd_printk("unable to grab IRQ %d\n", pci->irq);
-			return -EIO;
-		}
+	if ((ice->res_port = request_region(ice->port, 32, "ICE1712 - Controller")) == NULL) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->port, ice->port + 32 - 1);
+		return -EIO;
+	}
+	if ((ice->res_ddma_port = request_region(ice->ddma_port, 16, "ICE1712 - DDMA")) == NULL) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->ddma_port, ice->ddma_port + 16 - 1);
+		return -EIO;
+	}
+	if ((ice->res_dmapath_port = request_region(ice->dmapath_port, 16, "ICE1712 - DMA path")) == NULL) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->dmapath_port, ice->dmapath_port + 16 - 1);
+		return -EIO;
+	}
+	if ((ice->res_profi_port = request_region(ice->profi_port, 64, "ICE1712 - Professional")) == NULL) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->profi_port, ice->profi_port + 16 - 1);
+		return -EIO;
+	}
+	if (request_irq(pci->irq, snd_ice1712_interrupt, SA_INTERRUPT|SA_SHIRQ, "ICE1712", (void *) ice)) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab IRQ %d\n", pci->irq);
+		return -EIO;
+	}
 	
-		ice->irq = pci->irq;
-
-		if (snd_ice1712_read_eeprom(ice) < 0) {
-			snd_ice1712_free(ice);
-			return -EIO;
-		}
-		if (snd_ice1712_chip_init(ice) < 0) {
-			snd_ice1712_free(ice);
-			return -EIO;
-		}
+	ice->irq = pci->irq;
 
-		/* unmask used interrupts */
-		outb((ice->eeprom.codec & ICE1712_CFG_2xMPU401) == 0 ? ICE1712_IRQ_MPU2 : 0 |
-			 (ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97) ? ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0,
-			 ICEREG(ice, IRQMASK));
-		outb(0x00, ICEMT(ice, IRQ));
+	if (snd_ice1712_read_eeprom(ice) < 0) {
+		snd_ice1712_free(ice);
+		return -EIO;
 	}
+	if (snd_ice1712_chip_init(ice) < 0) {
+		snd_ice1712_free(ice);
+		return -EIO;
+	}
+
+	/* unmask used interrupts */
+	outb((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ? ICE1712_IRQ_MPU2 : 0 |
+	     (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ? ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0,
+	     ICEREG(ice, IRQMASK));
+	outb(0x00, ICEMT(ice, IRQ));
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops)) < 0) {
 		snd_ice1712_free(ice);
@@ -2866,7 +2451,6 @@
 	snd_ice1712_hoontech_cards,
 	snd_ice1712_delta_cards,
 	snd_ice1712_ews_cards,
-	snd_vt1724_amp_cards, 
 	0,
 };
 
@@ -2878,7 +2462,6 @@
 	snd_card_t *card;
 	ice1712_t *ice;
 	int pcm_dev = 0, err;
-	int chip_type;
 	struct snd_ice1712_card_info **tbl, *c;
 
 	if (dev >= SNDRV_CARDS)
@@ -2892,16 +2475,10 @@
 	if (card == NULL)
 		return -ENOMEM;
 
-	chip_type = pci_id->driver_data;
-	if (chip_type == TYPE_ICE1712) {
-		strcpy(card->driver, "ICE1712");
-		strcpy(card->shortname, "ICEnsemble ICE1712");
-	} else {
-		strcpy(card->driver, "ICE1724");
-		strcpy(card->shortname, "ICEnsemble ICE1724");
-	}
+	strcpy(card->driver, "ICE1712");
+	strcpy(card->shortname, "ICEnsemble ICE1712");
 	
-	if ((err = snd_ice1712_create(card, pci, chip_type, omni[dev], &ice)) < 0) {
+	if ((err = snd_ice1712_create(card, pci, omni[dev], &ice)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
@@ -2928,7 +2505,7 @@
 		return err;
 	}
 	
-	if (!(ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97))
+	if (ice_has_con_ac97(ice))
 		if ((err = snd_ice1712_pcm(ice, pcm_dev++, NULL)) < 0) {
 			snd_card_free(card);
 			return err;
@@ -2951,7 +2528,7 @@
 		}
 	}
 
-	if (!(ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97))
+	if (ice_has_con_ac97(ice))
 		if ((err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL)) < 0) {
 			snd_card_free(card);
 			return err;
@@ -2966,7 +2543,7 @@
 			return err;
 		}
 
-		if (ice->eeprom.codec & ICE1712_CFG_2xMPU401)
+		if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401)
 			if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
 						       ICEREG(ice, MPU2_CTRL), 1,
 						       ice->irq, 0,
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/ice1712.h linux-2.5.65-bk2/sound/pci/ice1712/ice1712.h
--- linux-2.5.65-bk1/sound/pci/ice1712/ice1712.h	Mon Mar 17 13:43:39 2003
+++ linux-2.5.65-bk2/sound/pci/ice1712/ice1712.h	Mon Mar 31 12:39:51 2003
@@ -214,50 +214,70 @@
  */
 
 typedef struct _snd_ice1712 ice1712_t;
-typedef struct snd_ak4524 ak4524_t;
+typedef struct snd_ak4xxx akm4xxx_t;
 
 typedef struct {
 	unsigned int subvendor;	/* PCI[2c-2f] */
 	unsigned char size;	/* size of EEPROM image in bytes */
-	unsigned char version;	/* must be 1 */
-	unsigned char codec;	/* codec configuration PCI[60] */
-	unsigned char aclink;	/* ACLink configuration PCI[61] */
-	unsigned char i2sID;	/* PCI[62] */
-	unsigned char spdif;	/* S/PDIF configuration PCI[63] */
-	unsigned char gpiomask;	/* GPIO initial mask, 0 = write, 1 = don't */
-	unsigned char gpiostate; /* GPIO initial state */
-	unsigned char gpiodir;	/* GPIO direction state */
-	unsigned short ac97main;
-	unsigned short ac97pcm;
-	unsigned short ac97rec;
-	unsigned char ac97recsrc;
-	unsigned char dacID[4];	/* I2S IDs for DACs */
-	unsigned char adcID[4];	/* I2S IDs for ADCs */
-	unsigned char extra[4];
+	unsigned char version;	/* must be 1 (or 2 for vt1724) */
+	unsigned char data[32];
+	unsigned int gpiomask;
+	unsigned int gpiostate;
+	unsigned int gpiodir;
 } ice1712_eeprom_t;
 
-struct snd_ak4524 {
+enum {
+	ICE_EEP1_CODEC = 0,	/* 06 */
+	ICE_EEP1_ACLINK,	/* 07 */
+	ICE_EEP1_I2SID,		/* 08 */
+	ICE_EEP1_SPDIF,		/* 09 */
+	ICE_EEP1_GPIO_MASK,	/* 0a */
+	ICE_EEP1_GPIO_STATE,	/* 0b */
+	ICE_EEP1_GPIO_DIR,	/* 0c */
+	ICE_EEP1_AC97_MAIN_LO,	/* 0d */
+	ICE_EEP1_AC97_MAIN_HI,	/* 0e */
+	ICE_EEP1_AC97_PCM_LO,	/* 0f */
+	ICE_EEP1_AC97_PCM_HI,	/* 10 */
+	ICE_EEP1_AC97_REC_LO,	/* 11 */
+	ICE_EEP1_AC97_REC_HI,	/* 12 */
+	ICE_EEP1_AC97_RECSRC,	/* 13 */
+	ICE_EEP1_DAC_ID,	/* 14 */
+	ICE_EEP1_DAC_ID1,
+	ICE_EEP1_DAC_ID2,
+	ICE_EEP1_DAC_ID3,
+	ICE_EEP1_ADC_ID,	/* 18 */
+	ICE_EEP1_ADC_ID1,
+	ICE_EEP1_ADC_ID2,
+	ICE_EEP1_ADC_ID3
+};
+	
+#define ice_has_con_ac97(ice)	(!((ice)->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97))
+
+
+struct snd_ak4xxx {
 	unsigned int num_adcs;		/* AK4524 or AK4528 ADCs */
 	unsigned int num_dacs;		/* AK4524 or AK4528 DACs */
-	unsigned char images[4][16];
-	unsigned char ipga_gain[4][2];
-	/* */
+	unsigned char images[4][16];	/* saved register image */
+	unsigned char ipga_gain[4][2];	/* saved register image for IPGA (AK4528) */
+	ice1712_t *chip;
+	/* template should fill the following fields */
+	unsigned int idx_offset;	/* control index offset */
 	enum {
-		SND_AK4524, SND_AK4528, SND_AK4529
+		SND_AK4524, SND_AK4528, SND_AK4529, SND_AK4355, SND_AK4381
 	} type;
-	unsigned int cif: 1;
-	unsigned char data_mask;
-	unsigned char clk_mask;
+	unsigned int cif: 1;		/* CIF mode */
 	unsigned char caddr;		/* C0 and C1 bits */
-	unsigned char cs_mask;
-	unsigned char cs_addr;
-	unsigned char cs_none;
-	unsigned char add_flags;
-	unsigned char mask_flags;
-	struct snd_ak4524_ops {
-		int (*start)(ice1712_t *, unsigned char *, int);
-		void (*stop)(ice1712_t *, unsigned char *);
-		void (*set_rate_val)(ice1712_t *, unsigned int);
+	unsigned int data_mask;		/* DATA gpio bit */
+	unsigned int clk_mask;		/* CLK gpio bit */
+	unsigned int cs_mask;		/* bit mask for select/deselect address */
+	unsigned int cs_addr;		/* bits to select address */
+	unsigned int cs_none;		/* bits to deselect address */
+	unsigned int add_flags;		/* additional bits at init */
+	unsigned int mask_flags;	/* total mask bits */
+	struct snd_akm4xxx_ops {
+		int (*start)(akm4xxx_t *ak, int chip);
+		void (*stop)(akm4xxx_t *ak);
+		void (*set_rate_val)(akm4xxx_t *ak, unsigned int rate);
 	} ops;
 };
 
@@ -268,7 +288,7 @@
 
 	struct snd_ice1712_spdif_ops {
 		void (*open)(ice1712_t *, snd_pcm_substream_t *);
-		void (*setup)(ice1712_t *, snd_pcm_substream_t *);
+		void (*setup_rate)(ice1712_t *, int rate);
 		void (*close)(ice1712_t *, snd_pcm_substream_t *);
 		void (*default_get)(ice1712_t *, snd_ctl_elem_value_t * ucontrol);
 		int (*default_put)(ice1712_t *, snd_ctl_elem_value_t * ucontrol);
@@ -294,8 +314,6 @@
 	unsigned long profi_port;
 	struct resource *res_profi_port;
 
-	unsigned int config;	/* system configuration */
-
 	struct pci_dev *pci;
 	snd_card_t *card;
 	snd_pcm_t *pcm;
@@ -316,19 +334,21 @@
 	snd_rawmidi_t *rmidi[2];
 
 	spinlock_t reg_lock;
-	struct semaphore gpio_mutex;
 	snd_info_entry_t *proc_entry;
 
 	ice1712_eeprom_t eeprom;
 
 	unsigned int pro_volumes[20];
-	int omni: 1;			/* Delta Omni I/O */
+	unsigned int omni: 1;		/* Delta Omni I/O */
+	unsigned int vt1724: 1;
 	unsigned int num_total_dacs;	/* total DACs */
 	unsigned char hoontech_boxbits[4];
 	unsigned int hoontech_config;
 	unsigned short hoontech_boxconfig[4];
+	unsigned int cur_rate;		/* current rate */
 
-	struct snd_ak4524 ak4524;
+	unsigned int akm_codecs;
+	akm4xxx_t *akm;
 	struct snd_ice1712_spdif spdif;
 
 	snd_i2c_bus_t *i2c;		/* I2C bus */
@@ -336,13 +356,67 @@
 	snd_i2c_device_t *cs8427;	/* CS8427 I2C device */
 	snd_i2c_device_t *i2cdevs[2];	/* additional i2c devices */
 	
-	unsigned int gpio_direction, gpio_write_mask;
-	int vt1724;
+	struct ice1712_gpio {
+		unsigned int direction;		/* current direction bits */
+		unsigned int write_mask;	/* current mask bits */
+		unsigned int saved[2];		/* for ewx_i2c */
+		/* operators */
+		void (*set_mask)(ice1712_t *ice, unsigned int data);
+		void (*set_dir)(ice1712_t *ice, unsigned int data);
+		void (*set_data)(ice1712_t *ice, unsigned int data);
+		unsigned int (*get_data)(ice1712_t *ice);
+	} gpio;
+	struct semaphore gpio_mutex;
 };
 
 #define chip_t ice1712_t
 
 
+/*
+ * gpio access functions
+ */
+static inline void snd_ice1712_gpio_set_dir(ice1712_t *ice, unsigned int bits)
+{
+	ice->gpio.set_dir(ice, bits);
+}
+
+static inline void snd_ice1712_gpio_set_mask(ice1712_t *ice, unsigned int bits)
+{
+	ice->gpio.set_mask(ice, bits);
+}
+
+static inline void snd_ice1712_gpio_write(ice1712_t *ice, unsigned int val)
+{
+	ice->gpio.set_data(ice, val);
+}
+
+static inline unsigned int snd_ice1712_gpio_read(ice1712_t *ice)
+{
+	return ice->gpio.get_data(ice);
+}
+
+/*
+ * save and restore gpio status
+ * The access to gpio will be protected by mutex, so don't forget to
+ * restore!
+ */
+static inline void snd_ice1712_save_gpio_status(ice1712_t *ice)
+{
+	down(&ice->gpio_mutex);
+	ice->gpio.saved[0] = ice->gpio.direction;
+	ice->gpio.saved[1] = ice->gpio.write_mask;
+}
+
+static inline void snd_ice1712_restore_gpio_status(ice1712_t *ice)
+{
+	ice->gpio.set_dir(ice, ice->gpio.saved[0]);
+	ice->gpio.set_mask(ice, ice->gpio.saved[1]);
+	ice->gpio.direction = ice->gpio.saved[0];
+	ice->gpio.write_mask = ice->gpio.saved[1];
+	up(&ice->gpio_mutex);
+}
+
+/* for bit controls */
 #define ICE1712_GPIO(xiface, xname, xindex, mask, invert, xaccess) \
 { .iface = xiface, .name = xname, .access = xaccess, .info = snd_ice1712_gpio_info, \
   .get = snd_ice1712_gpio_get, .put = snd_ice1712_gpio_put, \
@@ -352,17 +426,23 @@
 int snd_ice1712_gpio_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_ice1712_gpio_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 
-void snd_ice1712_gpio_write_bits(ice1712_t *ice, int mask, int bits);
-void snd_ice1712_save_gpio_status(ice1712_t *ice, unsigned char *tmp);
-void snd_ice1712_restore_gpio_status(ice1712_t *ice, unsigned char *tmp);
-
+/*
+ * set gpio direction, write mask and data
+ */
+static inline void snd_ice1712_gpio_write_bits(ice1712_t *ice, unsigned int mask, unsigned int bits)
+{
+	ice->gpio.direction |= mask;
+	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+	snd_ice1712_gpio_set_mask(ice, ~mask);
+	snd_ice1712_gpio_write(ice, mask & bits);
+}
 
 int snd_ice1712_spdif_build_controls(ice1712_t *ice);
 
-void snd_ice1712_ak4524_write(ice1712_t *ice, int chip, unsigned char addr, unsigned char data);
-void snd_ice1712_ak4524_reset(ice1712_t *ice, int state);
-void snd_ice1712_ak4524_init(ice1712_t *ice);
-int snd_ice1712_ak4524_build_controls(ice1712_t *ice);
+void snd_ice1712_akm4xxx_write(akm4xxx_t *ice, int chip, unsigned char addr, unsigned char data);
+void snd_ice1712_akm4xxx_reset(akm4xxx_t *ice, int state);
+void snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *template, ice1712_t *ice);
+int snd_ice1712_akm4xxx_build_controls(ice1712_t *ice);
 
 int snd_ice1712_init_cs8427(ice1712_t *ice, int addr);
 
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/ice1724.c linux-2.5.65-bk2/sound/pci/ice1712/ice1724.c
--- linux-2.5.65-bk1/sound/pci/ice1712/ice1724.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/sound/pci/ice1712/ice1724.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,1973 @@
+/*
+ *   ALSA driver for VT1724 ICEnsemble ICE1724 / VIA VT1724 (Envy24HT)
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *                    2002 James Stafford <jstafford@ampltd.com>
+ *                    2003 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/mpu401.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+#include <sound/asoundef.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+
+/* lowlevel routines */
+#include "amp.h"
+#include "revo.h"
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("ICEnsemble ICE1724 (Envy24HT)");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{"
+	       REVO_DEVICE_DESC
+	       AMP_AUDIO2000_DEVICE_DESC
+		"{VIA,VT1724},"
+		"{ICEnsemble,Generic ICE1724},"
+		"{ICEnsemble,Generic Envy24HT}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;		/* Enable this card */
+
+MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(index, "Index value for ICE1724 soundcard.");
+MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
+MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(id, "ID string for ICE1724 soundcard.");
+MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
+MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(enable, "Enable ICE1724 soundcard.");
+MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+
+#ifndef PCI_VENDOR_ID_ICE
+#define PCI_VENDOR_ID_ICE		0x1412
+#endif
+#ifndef PCI_DEVICE_ID_VT1724
+#define PCI_DEVICE_ID_VT1724		0x1724
+#endif
+
+static struct pci_device_id snd_vt1724_ids[] __devinitdata = {
+	{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_vt1724_ids);
+
+
+static int PRO_RATE_LOCKED = 0;
+static int PRO_RATE_RESET = 1;
+static unsigned int PRO_RATE_DEFAULT = 44100;
+
+/*
+ *  Basic I/O
+ */
+ 
+/* check whether the clock mode is spdif-in */
+static inline int is_spdif_master(ice1712_t *ice)
+{
+	return (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER) ? 1 : 0;
+}
+
+static inline int is_pro_rate_locked(ice1712_t *ice)
+{
+	return is_spdif_master(ice) || PRO_RATE_LOCKED;
+}
+
+/*
+ * ac97 section
+ */
+
+static unsigned char snd_vt1724_ac97_ready(ice1712_t *ice)
+{
+	unsigned char old_cmd;
+	int tm;
+	for (tm = 0; tm < 0x10000; tm++) {
+		old_cmd = inb(ICEMT1724(ice, AC97_CMD));
+		if (old_cmd & (VT1724_AC97_WRITE | VT1724_AC97_READ))
+			continue;
+		if (!(old_cmd & VT1724_AC97_READY))
+			continue;
+		return 0;
+	}
+	return old_cmd;
+}
+
+static int snd_vt1724_ac97_wait_bit(ice1712_t *ice, unsigned char bit)
+{
+	int tm;
+	for (tm = 0; tm < 0x10000; tm++)
+		if ((inb(ICEMT1724(ice, AC97_CMD)) & bit) == 0)
+			return 0;
+	return -EIO;
+}
+
+static void snd_vt1724_ac97_write(ac97_t *ac97,
+				  unsigned short reg,
+				  unsigned short val)
+{
+	ice1712_t *ice = (ice1712_t *)ac97->private_data;
+	unsigned char old_cmd;
+
+	old_cmd = snd_vt1724_ac97_ready(ice);
+	outb(reg, ICEMT1724(ice, AC97_INDEX));
+	outw(val, ICEMT1724(ice, AC97_DATA));
+	old_cmd &= ~(VT1724_AC97_PBK_VSR | VT1724_AC97_CAP_VSR);
+	outb(old_cmd | VT1724_AC97_WRITE, ICEMT1724(ice, AC97_CMD));
+	snd_vt1724_ac97_wait_bit(ice, VT1724_AC97_WRITE);
+}
+
+static unsigned short snd_vt1724_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+	ice1712_t *ice = (ice1712_t *)ac97->private_data;
+	unsigned char old_cmd;
+
+	old_cmd = snd_vt1724_ac97_ready(ice);
+	outb(reg, ICEMT1724(ice, AC97_INDEX));
+	outb(old_cmd | VT1724_AC97_READ, ICEMT1724(ice, AC97_CMD));
+	if (snd_vt1724_ac97_wait_bit(ice, VT1724_AC97_READ) < 0)
+		return ~0;
+	return inw(ICEMT1724(ice, AC97_DATA));
+}
+
+
+/*
+ * GPIO operations
+ */
+
+/* set gpio direction 0 = read, 1 = write */
+static void snd_vt1724_set_gpio_dir(ice1712_t *ice, unsigned int data)
+{
+	outl(data, ICEREG1724(ice, GPIO_DIRECTION));
+}
+
+/* set the gpio mask (0 = writable) */
+static void snd_vt1724_set_gpio_mask(ice1712_t *ice, unsigned int data)
+{
+	outw(data, ICEREG1724(ice, GPIO_WRITE_MASK));
+	outb((data >> 16) & 0xff, ICEREG1724(ice, GPIO_WRITE_MASK_22));
+}
+
+static void snd_vt1724_set_gpio_data(ice1712_t *ice, unsigned int data)
+{
+	outw(data, ICEREG1724(ice, GPIO_DATA));
+	outb(data >> 16, ICEREG1724(ice, GPIO_DATA_22));
+}
+
+static unsigned int snd_vt1724_get_gpio_data(ice1712_t *ice)
+{
+	unsigned int data;
+	data = (unsigned int)inb(ICEREG1724(ice, GPIO_DATA_22));
+	data = (data << 16) | inw(ICEREG1724(ice, GPIO_DATA));
+	return data;
+}
+
+/*
+ *  Interrupt handler
+ */
+
+static void snd_vt1724_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, dev_id, return);
+	unsigned char status;
+
+	while (1) {
+		status = inb(ICEREG1724(ice, IRQSTAT));
+		if (status == 0)
+			break;
+		
+		/*  these should probably be separated at some point, 
+			but as we don't currently have MPU support on the board I will leave it */
+		if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) {
+			if (ice->rmidi[0])
+				snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs);
+			outb(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX, ICEREG1724(ice, IRQSTAT));
+			status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX);
+		}
+		if (status & VT1724_IRQ_MTPCM) {
+			unsigned char mtstat = inb(ICEMT1724(ice, IRQ));
+			if (mtstat & VT1724_MULTI_PDMA0) {
+				if (ice->playback_pro_substream)
+					snd_pcm_period_elapsed(ice->playback_pro_substream);
+			}
+			if (mtstat & VT1724_MULTI_RDMA0) {
+				if (ice->capture_pro_substream)
+					snd_pcm_period_elapsed(ice->capture_pro_substream);
+			}
+			if (mtstat & VT1724_MULTI_PDMA4) {
+				if (ice->playback_con_substream)
+					snd_pcm_period_elapsed(ice->playback_con_substream);
+			}
+			if (mtstat & VT1724_MULTI_RDMA1) {
+				if (ice->capture_con_substream)
+					snd_pcm_period_elapsed(ice->capture_con_substream);
+			}
+			/* ack anyway to avoid freeze */
+			outb(mtstat, ICEMT1724(ice, IRQ));
+			/* ought to really handle this properly */
+			if (mtstat & VT1724_MULTI_FIFO_ERR) {
+				unsigned char fstat = inb(ICEMT1724(ice, DMA_FIFO_ERR));
+				outb(fstat, ICEMT1724(ice, DMA_FIFO_ERR));	
+				outb(VT1724_MULTI_FIFO_ERR | inb(ICEMT1724(ice, DMA_INT_MASK)), ICEMT1724(ice, DMA_INT_MASK));	
+				/* If I don't do this, I get machine lockup due to continual interrupts */
+			}
+
+		}
+	}
+}
+
+/*
+ *  PCM code - professional part (multitrack)
+ */
+
+static unsigned int rates[] = {
+	8000, 9600, 11025, 12000, 16000, 22050, 24000,
+	32000, 44100, 48000, 64000, 88200, 96000,
+	176400, 192000,
+};
+
+static snd_pcm_hw_constraint_list_t hw_constraints_rates_96 = {
+	.count = ARRAY_SIZE(rates) - 2, /* up to 96000 */
+	.list = rates,
+	.mask = 0,
+};
+
+static snd_pcm_hw_constraint_list_t hw_constraints_rates_192 = {
+	.count = ARRAY_SIZE(rates),
+	.list = rates,
+	.mask = 0,
+};
+
+static unsigned int hw_channels[] = {
+	2, 4, 6, 8
+};
+
+static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
+	.count = ARRAY_SIZE(hw_channels),
+	.list = hw_channels,
+	.mask = 0,
+};
+
+static int snd_vt1724_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	unsigned int what;
+	unsigned int old;
+	snd_pcm_substream_t *s;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		what = 0;
+		s = substream;
+		do {
+			if (s == ice->playback_pro_substream)
+				what |= VT1724_PDMA0_PAUSE;
+			else if (s == ice->capture_pro_substream)
+				what |= VT1724_RDMA0_PAUSE;
+			else if (s == ice->playback_con_substream)
+				what |= VT1724_PDMA4_PAUSE;
+			else if (s == ice->capture_con_substream)
+				what |= VT1724_RDMA1_PAUSE;
+			s = s->link_next;
+		} while (s != substream);
+		spin_lock(&ice->reg_lock);
+		old = inl(ICEMT1724(ice, DMA_PAUSE));
+		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
+			old |= what;
+		else
+			old &= ~what;
+		outl(old, ICEMT1724(ice, DMA_PAUSE));
+		spin_unlock(&ice->reg_lock);
+		break;
+
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_STOP:
+		what = 0;
+		s = substream;
+		do {
+			if (s == ice->playback_pro_substream) {
+				what |= VT1724_PDMA0_START;
+				snd_pcm_trigger_done(s, substream);
+			} else if (s == ice->capture_pro_substream) {
+				what |= VT1724_RDMA0_START;
+				snd_pcm_trigger_done(s, substream);
+			} else if (s == ice->playback_con_substream) {
+				what |= VT1724_PDMA4_START;
+				snd_pcm_trigger_done(s, substream);
+			} else if (s == ice->capture_con_substream) {
+				what |= VT1724_RDMA1_START;
+				snd_pcm_trigger_done(s, substream);
+			}
+			s = s->link_next;
+		} while (s != substream);
+		spin_lock(&ice->reg_lock);
+		old = inl(ICEMT1724(ice, DMA_CONTROL));
+		if (cmd == SNDRV_PCM_TRIGGER_START)
+			old |= what;
+		else
+			old &= ~what;
+		outl(old, ICEMT1724(ice, DMA_CONTROL));
+		spin_unlock(&ice->reg_lock);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ */
+
+#define DMA_STARTS	(VT1724_RDMA0_START|VT1724_PDMA0_START|VT1724_RDMA1_START|VT1724_PDMA4_START)
+#define DMA_PAUSES	(VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|VT1724_PDMA4_PAUSE)
+
+static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force)
+{
+	unsigned long flags;
+	unsigned char val, old;
+	unsigned int i;
+
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || 
+	    (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
+		/* running? we cannot change the rate now... */
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		return;
+	}
+	if (!force && is_pro_rate_locked(ice)) {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		return;
+	}
+
+	if (rate == ice->cur_rate) {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		return;
+	}
+
+	switch (rate) {
+	case 8000: val = 6; break;
+	case 9600: val = 3; break;
+	case 11025: val = 10; break;
+	case 12000: val = 2; break;
+	case 16000: val = 5; break;
+	case 22050: val = 9; break;
+	case 24000: val = 1; break;
+	case 32000: val = 4; break;
+	case 44100: val = 8; break;
+	case 48000: val = 0; break;
+	case 64000: val = 15; break;
+	case 88200: val = 11; break;
+	case 96000: val = 7; break;
+	case 176400: val = 12; break;
+	case 192000: val = 14; break;
+	default:
+		snd_BUG();
+		val = 0;
+		break;
+	}
+	outb(val, ICEMT1724(ice, RATE));
+	ice->cur_rate = rate;
+
+	/* check MT02 */
+	if (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) {
+		val = old = inb(ICEMT1724(ice, I2S_FORMAT));
+		if (rate > 96000)
+			val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */
+		else
+			val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */
+		if (val != old) {
+			outb(val, ICEMT1724(ice, I2S_FORMAT));
+			/* FIXME: is this revo only? */
+			/* assert PRST# to converters; MT05 bit 7 */
+			outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD));
+			spin_unlock_irqrestore(&ice->reg_lock, flags);
+			mdelay(5);
+			spin_lock_irqsave(&ice->reg_lock, flags);
+			/* deassert PRST# */
+			outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
+		}
+	}
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+
+	/* set up codecs */
+	for (i = 0; i < ice->akm_codecs; i++) {
+		if (ice->akm[i].ops.set_rate_val)
+			ice->akm[i].ops.set_rate_val(&ice->akm[i], rate);
+	}
+}
+
+static int snd_vt1724_pcm_hw_params(snd_pcm_substream_t * substream,
+				    snd_pcm_hw_params_t * hw_params)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+static int snd_vt1724_pcm_hw_free(snd_pcm_substream_t * substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_vt1724_playback_pro_prepare(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	unsigned char val;
+	unsigned int size;
+
+	spin_lock(&ice->reg_lock);
+	val = (8 - substream->runtime->channels) >> 1;
+	outb(val, ICEMT1724(ice, BURST));
+
+	outl(substream->runtime->dma_addr, ICEMT1724(ice, PLAYBACK_ADDR));
+
+	size = (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1;
+	// outl(size, ICEMT1724(ice, PLAYBACK_SIZE));
+	outw(size, ICEMT1724(ice, PLAYBACK_SIZE));
+	outb(size >> 16, ICEMT1724(ice, PLAYBACK_SIZE) + 2);
+	size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1;
+	// outl(size, ICEMT1724(ice, PLAYBACK_COUNT));
+	outw(size, ICEMT1724(ice, PLAYBACK_COUNT));
+	outb(size >> 16, ICEMT1724(ice, PLAYBACK_COUNT) + 2);
+
+	spin_unlock(&ice->reg_lock);
+
+	// printk("pro prepare: ch = %d, addr = 0x%x, buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream));
+	return 0;
+}
+
+#define CHECK_INVALID_PTR
+
+static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & VT1724_PDMA0_START))
+		return 0;
+	ptr = inl(ICEMT1724(ice, PLAYBACK_ADDR));
+#ifdef CHECK_INVALID_PTR
+	if (ptr < substream->runtime->dma_addr) {
+		snd_printd("ice1724: invalid negative ptr\n");
+		return 0;
+	}
+#endif
+	ptr -= substream->runtime->dma_addr;
+	ptr = bytes_to_frames(substream->runtime, ptr);
+#ifdef CHECK_INVALID_PTR
+	if (ptr >= substream->runtime->buffer_size) {
+		snd_printd("ice1724: invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->period_size);
+		return 0;
+	}
+#endif
+	return ptr;
+}
+
+struct vt1724_pcm_reg {
+	unsigned int addr;	/* ADDR register offset */
+	unsigned int size;	/* SIZE register offset */
+	unsigned int count;	/* COUNT register offset */
+	unsigned int start;	/* start bit */
+	unsigned int pause;	/* pause bit */
+};
+
+static int snd_vt1724_pcm_prepare(snd_pcm_substream_t *substream, const struct vt1724_pcm_reg *reg)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	spin_lock(&ice->reg_lock);
+	outl(substream->runtime->dma_addr, ice->profi_port + reg->addr);
+	outw((snd_pcm_lib_buffer_bytes(substream) >> 2) - 1, ice->profi_port + reg->size);
+	outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ice->profi_port + reg->count);
+	spin_unlock(&ice->reg_lock);
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_vt1724_pcm_pointer(snd_pcm_substream_t *substream, const struct vt1724_pcm_reg *reg)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start))
+		return 0;
+	ptr = inl(ice->profi_port + reg->addr);
+	ptr -= substream->runtime->dma_addr;
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+const static struct vt1724_pcm_reg vt1724_capture_pro_reg = {
+	.addr = VT1724_MT_CAPTURE_ADDR,
+	.size = VT1724_MT_CAPTURE_SIZE,
+	.count = VT1724_MT_CAPTURE_COUNT,
+	.start = VT1724_RDMA0_START,
+	.pause = VT1724_RDMA0_PAUSE,
+};
+
+static int snd_vt1724_capture_pro_prepare(snd_pcm_substream_t * substream)
+{
+	return snd_vt1724_pcm_prepare(substream, &vt1724_capture_pro_reg);
+}
+
+static snd_pcm_uframes_t snd_vt1724_capture_pro_pointer(snd_pcm_substream_t * substream)
+{
+	return snd_vt1724_pcm_pointer(substream, &vt1724_capture_pro_reg);
+}
+
+static snd_pcm_hardware_t snd_vt1724_playback_pro =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
+	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
+	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000,
+	.rate_min =		4000,
+	.rate_max =		192000,
+	.channels_min =		2,
+	.channels_max =		8,
+	.buffer_bytes_max =	(1UL << 21),	/* 18bits dword */
+	.period_bytes_min =	8 * 4 * 2,	/* FIXME: constraints needed */
+	.period_bytes_max =	(1UL << 21),
+	.periods_min =		1,
+	.periods_max =		1024,
+};
+
+static snd_pcm_hardware_t snd_vt1724_capture_pro =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
+	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
+	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000,
+	.rate_min =		4000,
+	.rate_max =		192000,
+	.channels_min =		2,
+	.channels_max =		2,
+	.buffer_bytes_max =	(256*1024),
+	.period_bytes_min =	2 * 4 * 2,
+	.period_bytes_max =	(256*1024),
+	.periods_min =		1,
+	.periods_max =		1024,
+};
+
+/* multi-channel playback needs alignment 8x32bit regarless of the channels
+ * actually used
+ */
+#define VT1724_BUFFER_ALIGN	0x20
+
+static int snd_vt1724_playback_pro_open(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->playback_pro_substream = substream;
+	runtime->hw = snd_vt1724_playback_pro;
+	snd_pcm_set_sync(substream);
+	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+	if ((ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) &&
+	    (ice->eeprom.data[ICE_EEP2_I2S] & 0x08))
+		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192);
+	else
+		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
+
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+				   VT1724_BUFFER_ALIGN);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+				   VT1724_BUFFER_ALIGN);
+	return 0;
+}
+
+static int snd_vt1724_capture_pro_open(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	ice->capture_pro_substream = substream;
+	runtime->hw = snd_vt1724_capture_pro;
+	snd_pcm_set_sync(substream);
+	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+	if ((ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) &&
+	    (ice->eeprom.data[ICE_EEP2_I2S] & 0x08))
+		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192);
+	else
+		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
+	return 0;
+}
+
+static int snd_vt1724_playback_pro_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	if (PRO_RATE_RESET)
+		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+	ice->playback_pro_substream = NULL;
+
+	return 0;
+}
+
+static int snd_vt1724_capture_pro_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	if (PRO_RATE_RESET)
+		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+	ice->capture_pro_substream = NULL;
+	return 0;
+}
+
+static snd_pcm_ops_t snd_vt1724_playback_pro_ops = {
+	.open =		snd_vt1724_playback_pro_open,
+	.close =	snd_vt1724_playback_pro_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_vt1724_pcm_hw_params,
+	.hw_free =	snd_vt1724_pcm_hw_free,
+	.prepare =	snd_vt1724_playback_pro_prepare,
+	.trigger =	snd_vt1724_pcm_trigger,
+	.pointer =	snd_vt1724_playback_pro_pointer,
+};
+
+static snd_pcm_ops_t snd_vt1724_capture_pro_ops = {
+	.open =		snd_vt1724_capture_pro_open,
+	.close =	snd_vt1724_capture_pro_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_vt1724_pcm_hw_params,
+	.hw_free =	snd_vt1724_pcm_hw_free,
+	.prepare =	snd_vt1724_capture_pro_prepare,
+	.trigger =	snd_vt1724_pcm_trigger,
+	.pointer =	snd_vt1724_capture_pro_pointer,
+};
+
+static int __devinit snd_vt1724_pcm_profi(ice1712_t * ice, int device)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	err = snd_pcm_new(ice->card, "ICE1724", device, 1, 1, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vt1724_playback_pro_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vt1724_capture_pro_ops);
+
+	pcm->private_data = ice;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "ICE1724");
+
+	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 256*1024, 256*1024);
+
+	ice->pcm_pro = pcm;
+
+	return 0;
+}
+
+
+/*
+ * SPDIF PCM
+ */
+
+static snd_pcm_hardware_t snd_vt1724_playback_spdif =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
+	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
+	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000,
+	.rate_min =		4000,
+	.rate_max =		192000,
+	.channels_min =		2,
+	.channels_max =		2,
+	.buffer_bytes_max =	(256*1024),
+	.period_bytes_min =	2 * 4 * 2,
+	.period_bytes_max =	(256*1024),
+	.periods_min =		1,
+	.periods_max =		1024,
+};
+
+const static struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
+	.addr = VT1724_MT_PDMA4_ADDR,
+	.size = VT1724_MT_PDMA4_SIZE,
+	.count = VT1724_MT_PDMA4_COUNT,
+	.start = VT1724_PDMA4_START,
+	.pause = VT1724_PDMA4_PAUSE,
+};
+
+const static struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
+	.addr = VT1724_MT_RDMA1_ADDR,
+	.size = VT1724_MT_RDMA1_SIZE,
+	.count = VT1724_MT_RDMA1_COUNT,
+	.start = VT1724_RDMA1_START,
+	.pause = VT1724_RDMA1_PAUSE,
+};
+
+static int snd_vt1724_playback_spdif_prepare(snd_pcm_substream_t * substream)
+{
+	return snd_vt1724_pcm_prepare(substream, &vt1724_playback_spdif_reg);
+}
+
+static snd_pcm_uframes_t snd_vt1724_playback_spdif_pointer(snd_pcm_substream_t * substream)
+{
+	return snd_vt1724_pcm_pointer(substream, &vt1724_playback_spdif_reg);
+}
+
+static int snd_vt1724_capture_spdif_prepare(snd_pcm_substream_t * substream)
+{
+	return snd_vt1724_pcm_prepare(substream, &vt1724_capture_spdif_reg);
+}
+
+static snd_pcm_uframes_t snd_vt1724_capture_spdif_pointer(snd_pcm_substream_t * substream)
+{
+	return snd_vt1724_pcm_pointer(substream, &vt1724_capture_spdif_reg);
+}
+
+static int snd_vt1724_playback_spdif_open(snd_pcm_substream_t *substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	ice->playback_con_substream = substream;
+	runtime->hw = snd_vt1724_playback_spdif;
+	snd_pcm_set_sync(substream);
+	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
+	return 0;
+}
+
+static int snd_vt1724_playback_spdif_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	if (PRO_RATE_RESET)
+		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+	ice->playback_con_substream = NULL;
+
+	return 0;
+}
+
+static int snd_vt1724_capture_spdif_open(snd_pcm_substream_t *substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	ice->capture_con_substream = substream;
+	runtime->hw = snd_vt1724_playback_spdif;
+	snd_pcm_set_sync(substream);
+	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
+	return 0;
+}
+
+static int snd_vt1724_capture_spdif_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	if (PRO_RATE_RESET)
+		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+	ice->capture_con_substream = NULL;
+
+	return 0;
+}
+
+static snd_pcm_ops_t snd_vt1724_playback_spdif_ops = {
+	.open =		snd_vt1724_playback_spdif_open,
+	.close =	snd_vt1724_playback_spdif_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_vt1724_pcm_hw_params,
+	.hw_free =	snd_vt1724_pcm_hw_free,
+	.prepare =	snd_vt1724_playback_spdif_prepare,
+	.trigger =	snd_vt1724_pcm_trigger,
+	.pointer =	snd_vt1724_playback_spdif_pointer,
+};
+
+static snd_pcm_ops_t snd_vt1724_capture_spdif_ops = {
+	.open =		snd_vt1724_capture_spdif_open,
+	.close =	snd_vt1724_capture_spdif_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_vt1724_pcm_hw_params,
+	.hw_free =	snd_vt1724_pcm_hw_free,
+	.prepare =	snd_vt1724_capture_spdif_prepare,
+	.trigger =	snd_vt1724_pcm_trigger,
+	.pointer =	snd_vt1724_capture_spdif_pointer,
+};
+
+
+static int __devinit snd_vt1724_pcm_spdif(ice1712_t * ice, int device)
+{
+	snd_pcm_t *pcm;
+	int play, capt;
+	int err;
+
+	if (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_OUT_INT)
+		play = 1;
+	else
+		play = 0;
+	if (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_IN)
+		capt = 1;
+	else
+		capt = 0;
+	if (! play && ! capt)
+		return 0; /* no spdif device */
+
+	err = snd_pcm_new(ice->card, "ICE1724 IEC958", device, play, capt, &pcm);
+	if (err < 0)
+		return err;
+
+	if (play)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				&snd_vt1724_playback_spdif_ops);
+	if (capt)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+				&snd_vt1724_capture_spdif_ops);
+
+	pcm->private_data = ice;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "ICE1724 IEC958");
+
+	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 64*1024);
+
+	ice->pcm = pcm;
+
+	return 0;
+}
+
+
+/*
+ *  Mixer section
+ */
+
+static int __devinit snd_vt1724_ac97_mixer(ice1712_t * ice)
+{
+	int err;
+
+	if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) {
+		ac97_t ac97;
+		memset(&ac97, 0, sizeof(ac97));
+		ac97.write = snd_vt1724_ac97_write;
+		ac97.read = snd_vt1724_ac97_read;
+		ac97.private_data = ice;
+		if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0)
+			printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
+		else
+			return 0;
+	}
+	/* I2S mixer only */
+	strcat(ice->card->mixername, "ICE1724 - multitrack");
+	return 0;
+}
+
+/*
+ *
+ */
+
+static inline unsigned int eeprom_triple(ice1712_t *ice, int idx)
+{
+	return (unsigned int)ice->eeprom.data[idx] | \
+		((unsigned int)ice->eeprom.data[idx + 1] << 8) | \
+		((unsigned int)ice->eeprom.data[idx + 2] << 16);
+}
+
+static void snd_vt1724_proc_read(snd_info_entry_t *entry, 
+				 snd_info_buffer_t * buffer)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, entry->private_data, return);
+	unsigned int idx;
+
+	snd_iprintf(buffer, "%s\n\n", ice->card->longname);
+	snd_iprintf(buffer, "EEPROM:\n");
+
+	snd_iprintf(buffer, "  Subvendor        : 0x%x\n", ice->eeprom.subvendor);
+	snd_iprintf(buffer, "  Size             : %i bytes\n", ice->eeprom.size);
+	snd_iprintf(buffer, "  Version          : %i\n", ice->eeprom.version);
+	snd_iprintf(buffer, "  System Config    : 0x%x\n", ice->eeprom.data[ICE_EEP2_SYSCONF]);
+	snd_iprintf(buffer, "  ACLink           : 0x%x\n", ice->eeprom.data[ICE_EEP2_ACLINK]);
+	snd_iprintf(buffer, "  I2S              : 0x%x\n", ice->eeprom.data[ICE_EEP2_I2S]);
+	snd_iprintf(buffer, "  S/PDIF           : 0x%x\n", ice->eeprom.data[ICE_EEP2_SPDIF]);
+	snd_iprintf(buffer, "  GPIO direction   : 0x%x\n", ice->eeprom.gpiodir);
+	snd_iprintf(buffer, "  GPIO mask        : 0x%x\n", ice->eeprom.gpiomask);
+	snd_iprintf(buffer, "  GPIO state       : 0x%x\n", ice->eeprom.gpiostate);
+	for (idx = 0x12; idx < ice->eeprom.size; idx++)
+		snd_iprintf(buffer, "  Extra #%02i        : 0x%x\n", idx, ice->eeprom.data[idx]);
+
+	snd_iprintf(buffer, "\nRegisters:\n");
+
+	snd_iprintf(buffer, "  PSDOUT03 : 0x%08x\n", (unsigned)inl(ICEMT1724(ice, ROUTE_PLAYBACK)));
+	for (idx = 0x0; idx < 0x20 ; idx++)
+		snd_iprintf(buffer, "  CCS%02x    : 0x%02x\n", idx, inb(ice->port+idx));
+	for (idx = 0x0; idx < 0x30 ; idx++)
+		snd_iprintf(buffer, "  MT%02x     : 0x%02x\n", idx, inb(ice->profi_port+idx));
+}
+
+static void __devinit snd_vt1724_proc_init(ice1712_t * ice)
+{
+	snd_info_entry_t *entry;
+
+	if (! snd_card_proc_new(ice->card, "ice1724", &entry))
+		snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read);
+}
+
+/*
+ *
+ */
+
+static int snd_vt1724_eeprom_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof(ice1712_eeprom_t);
+	return 0;
+}
+
+static int snd_vt1724_eeprom_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	
+	memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom));
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_vt1724_eeprom __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
+	.name = "ICE1724 EEPROM",
+	.access = SNDRV_CTL_ELEM_ACCESS_READ,
+	.info = snd_vt1724_eeprom_info,
+	.get = snd_vt1724_eeprom_get
+};
+
+/*
+ */
+static int snd_vt1724_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static unsigned int encode_spdif_bits(snd_aes_iec958_t *diga)
+{
+	unsigned int val;
+
+	val = diga->status[0] & 0x03; /* professional, non-audio */
+	if (val & 0x01) {
+		/* professional */
+		if ((diga->status[0] & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015)
+			val |= 1U << 3;
+		switch (diga->status[0] & IEC958_AES0_PRO_FS) {
+		case IEC958_AES0_PRO_FS_44100:
+			break;
+		case IEC958_AES0_PRO_FS_32000:
+			val |= 3U << 12;
+			break;
+		default:
+			val |= 2U << 12;
+			break;
+		}
+	} else {
+		/* consumer */
+		val |= diga->status[0] & 0x04; /* copyright */
+		if ((diga->status[0] & IEC958_AES0_CON_EMPHASIS)== IEC958_AES0_CON_EMPHASIS_5015)
+			val |= 1U << 3;
+		val |= (unsigned int)(diga->status[1] & 0x3f) << 4; /* category */
+		val |= (unsigned int)(diga->status[3] & IEC958_AES3_CON_FS) << 12; /* fs */
+	}
+	return val;
+}
+
+static void decode_spdif_bits(snd_aes_iec958_t *diga, unsigned int val)
+{
+	memset(diga->status, 0, sizeof(diga->status));
+	diga->status[0] = val & 0x03; /* professional, non-audio */
+	if (val & 0x01) {
+		/* professional */
+		if (val & (1U << 3))
+			diga->status[0] |= IEC958_AES0_PRO_EMPHASIS_5015;
+		switch ((val >> 12) & 0x7) {
+		case 0:
+			break;
+		case 2:
+			diga->status[0] |= IEC958_AES0_PRO_FS_32000;
+			break;
+		default:
+			diga->status[0] |= IEC958_AES0_PRO_FS_48000;
+			break;
+		}
+	} else {
+		/* consumer */
+		diga->status[0] |= val & (1U << 2); /* copyright */
+		if (val & (1U << 3))
+			diga->status[0] |= IEC958_AES0_CON_EMPHASIS_5015;
+		diga->status[1] |= (val >> 4) & 0x3f; /* category */
+		diga->status[3] |= (val >> 12) & 0x07; /* fs */
+	}
+}
+
+static int snd_vt1724_spdif_default_get(snd_kcontrol_t * kcontrol,
+					snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	val = inw(ICEMT1724(ice, SPDIF_CTRL));
+	decode_spdif_bits(&ucontrol->value.iec958, val);
+	return 0;
+}
+
+static int snd_vt1724_spdif_default_put(snd_kcontrol_t * kcontrol,
+					 snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned int val, old;
+	unsigned long flags;
+
+	val = encode_spdif_bits(&ucontrol->value.iec958);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	old = inw(ICEMT1724(ice, SPDIF_CTRL));
+	if (val != old) {
+		unsigned char cbit, disabled;
+		cbit = inb(ICEREG1724(ice, SPDIF_CFG));
+		disabled = cbit & ~VT1724_CFG_SPDIF_OUT_EN;
+		if (cbit != disabled)
+			outb(disabled, ICEREG1724(ice, SPDIF_CFG));
+		outw(val, ICEMT1724(ice, SPDIF_CTRL));
+		if (cbit != disabled)
+			outb(cbit, ICEREG1724(ice, SPDIF_CFG));
+	}
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return (val != old);
+}
+
+static snd_kcontrol_new_t snd_vt1724_spdif_default __devinitdata =
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+	.info =		snd_vt1724_spdif_info,
+	.get =		snd_vt1724_spdif_default_get,
+	.put =		snd_vt1724_spdif_default_put
+};
+
+static int snd_vt1724_spdif_maskc_get(snd_kcontrol_t * kcontrol,
+				       snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO |
+						     IEC958_AES0_PROFESSIONAL |
+						     IEC958_AES0_CON_NOT_COPYRIGHT |
+						     IEC958_AES0_CON_EMPHASIS;
+	ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL |
+						     IEC958_AES1_CON_CATEGORY;
+	ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
+	return 0;
+}
+
+static int snd_vt1724_spdif_maskp_get(snd_kcontrol_t * kcontrol,
+				       snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO |
+						     IEC958_AES0_PROFESSIONAL |
+						     IEC958_AES0_PRO_FS |
+						     IEC958_AES0_PRO_EMPHASIS;
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+	.info =		snd_vt1724_spdif_info,
+	.get =		snd_vt1724_spdif_maskc_get,
+};
+
+static snd_kcontrol_new_t snd_vt1724_spdif_maskp __devinitdata =
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+	.info =		snd_vt1724_spdif_info,
+	.get =		snd_vt1724_spdif_maskp_get,
+};
+
+static int snd_vt1724_spdif_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_vt1724_spdif_sw_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = inb(ICEREG1724(ice, SPDIF_CFG)) & VT1724_CFG_SPDIF_OUT_EN ? 1 : 0;
+	return 0;
+}
+
+static int snd_vt1724_spdif_sw_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char old, val;
+	unsigned long flags;
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	old = val = inb(ICEREG1724(ice, SPDIF_CFG));
+	val &= ~VT1724_CFG_SPDIF_OUT_EN;
+	if (ucontrol->value.integer.value[0])
+		val |= VT1724_CFG_SPDIF_OUT_EN;
+	if (old != val)
+		outb(val, ICEREG1724(ice, SPDIF_CFG));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return old != val;
+}
+
+static snd_kcontrol_new_t snd_vt1724_spdif_switch __devinitdata =
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* FIXME: the following conflict with IEC958 Playback Route */
+	// .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
+	.name =         "IEC958 Output Switch",
+	.info =		snd_vt1724_spdif_sw_info,
+	.get =		snd_vt1724_spdif_sw_get,
+	.put =		snd_vt1724_spdif_sw_put
+};
+
+
+#if 0 /* NOT USED YET */
+/*
+ * GPIO access from extern
+ */
+
+int snd_vt1724_gpio_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+int snd_vt1724_gpio_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value & 0xff;
+	int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0;
+	
+	snd_ice1712_save_gpio_status(ice);
+	ucontrol->value.integer.value[0] = (snd_ice1712_gpio_read(ice) & (1 << shift) ? 1 : 0) ^ invert;
+	snd_ice1712_restore_gpio_status(ice);
+	return 0;
+}
+
+int snd_ice1712_gpio_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value & 0xff;
+	int invert = (kcontrol->private_value & (1<<24)) ? mask : 0;
+	unsigned int val, nval;
+
+	if (kcontrol->private_value & (1 << 31))
+		return -EPERM;
+	nval = (ucontrol->value.integer.value[0] ? (1 << shift) : 0) ^ invert;
+	snd_ice1712_save_gpio_status(ice);
+	val = snd_ice1712_gpio_read(ice);
+	nval |= val & ~(1 << shift);
+	if (val != nval)
+		snd_ice1712_gpio_write(ice, nval);
+	snd_ice1712_restore_gpio_status(ice);
+	return val != nval;
+}
+#endif /* NOT USED YET */
+
+/*
+ *  rate
+ */
+static int snd_vt1724_pro_internal_clock_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[] = {
+		"8000",		/* 0: 6 */
+		"9600",		/* 1: 3 */
+		"11025",	/* 2: 10 */
+		"12000",	/* 3: 2 */
+		"16000",	/* 4: 5 */
+		"22050",	/* 5: 9 */
+		"24000",	/* 6: 1 */
+		"32000",	/* 7: 4 */
+		"44100",	/* 8: 8 */
+		"48000",	/* 9: 0 */
+		"64000",	/* 10: 15 */
+		"88200",	/* 11: 11 */
+		"96000",	/* 12: 7 */
+		"176400",	/* 13: 12 */
+		"192000",	/* 14: 14 */
+		"IEC958 Input",	/* 15: -- */
+	};
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 16;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_vt1724_pro_internal_clock_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	static unsigned char xlate[16] = {
+		9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10
+	};
+	unsigned char val;
+	
+	spin_lock_irq(&ice->reg_lock);
+	if (is_spdif_master(ice)) {
+		ucontrol->value.enumerated.item[0] = 15;
+	} else {
+		val = xlate[inb(ICEMT1724(ice, RATE)) & 15];
+		if (val == 255) {
+			snd_BUG();
+			val = 0;
+		}
+		ucontrol->value.enumerated.item[0] = val;
+	}
+	spin_unlock_irq(&ice->reg_lock);
+	return 0;
+}
+
+static int snd_vt1724_pro_internal_clock_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char oval;
+	int change = 0;
+
+	spin_lock_irq(&ice->reg_lock);
+	oval = inb(ICEMT1724(ice, RATE));
+	if (ucontrol->value.enumerated.item[0] == 15) {
+		outb(oval | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
+	} else {
+		PRO_RATE_DEFAULT = rates[ucontrol->value.integer.value[0] % 15];
+		spin_unlock_irq(&ice->reg_lock);
+		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 1);
+		spin_lock_irq(&ice->reg_lock);
+	}
+	change = inb(ICEMT1724(ice, RATE)) != oval;
+	spin_unlock_irq(&ice->reg_lock);
+
+	if ((oval & VT1724_SPDIF_MASTER) != (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER)) {
+		/* notify akm chips as well */
+		if (is_spdif_master(ice)) {
+			unsigned int i;
+			for (i = 0; i < ice->akm_codecs; i++) {
+				if (ice->akm[i].ops.set_rate_val)
+					ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
+			}
+		}
+	}
+	return change;
+}
+
+static snd_kcontrol_new_t snd_vt1724_pro_internal_clock = __devinitdata {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Multi Track Internal Clock",
+	.info = snd_vt1724_pro_internal_clock_info,
+	.get = snd_vt1724_pro_internal_clock_get,
+	.put = snd_vt1724_pro_internal_clock_put
+};
+
+static int snd_vt1724_pro_rate_locking_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_vt1724_pro_rate_locking_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.integer.value[0] = PRO_RATE_LOCKED;
+	return 0;
+}
+
+static int snd_vt1724_pro_rate_locking_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int change = 0, nval;
+
+	nval = ucontrol->value.integer.value[0] ? 1 : 0;
+	spin_lock_irq(&ice->reg_lock);
+	change = PRO_RATE_LOCKED != nval;
+	PRO_RATE_LOCKED = nval;
+	spin_unlock_irq(&ice->reg_lock);
+	return change;
+}
+
+static snd_kcontrol_new_t snd_vt1724_pro_rate_locking __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Multi Track Rate Locking",
+	.info = snd_vt1724_pro_rate_locking_info,
+	.get = snd_vt1724_pro_rate_locking_get,
+	.put = snd_vt1724_pro_rate_locking_put
+};
+
+static int snd_vt1724_pro_rate_reset_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_vt1724_pro_rate_reset_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.integer.value[0] = PRO_RATE_RESET ? 1 : 0;
+	return 0;
+}
+
+static int snd_vt1724_pro_rate_reset_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int change = 0, nval;
+
+	nval = ucontrol->value.integer.value[0] ? 1 : 0;
+	spin_lock_irq(&ice->reg_lock);
+	change = PRO_RATE_RESET != nval;
+	PRO_RATE_RESET = nval;
+	spin_unlock_irq(&ice->reg_lock);
+	return change;
+}
+
+static snd_kcontrol_new_t snd_vt1724_pro_rate_reset __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Multi Track Rate Reset",
+	.info = snd_vt1724_pro_rate_reset_info,
+	.get = snd_vt1724_pro_rate_reset_get,
+	.put = snd_vt1724_pro_rate_reset_put
+};
+
+
+/*
+ * routing
+ */
+static int snd_vt1724_pro_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[] = {
+		"PCM Out", /* 0 */
+		"H/W In 0", "H/W In 1", /* 1-2 */
+		"IEC958 In L", "IEC958 In R", /* 3-4 */
+	};
+	
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 5;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static inline int analog_route_shift(int idx)
+{
+	return (idx % 2) * 12 + ((idx / 2) * 3) + 8;
+}
+
+static inline int digital_route_shift(int idx)
+{
+	return idx * 3;
+}
+
+static int get_route_val(ice1712_t *ice, int shift)
+{
+	unsigned long val;
+	unsigned char eitem;
+	static unsigned char xlate[8] = {
+		0, 255, 1, 2, 255, 255, 3, 4,
+	};
+
+	val = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
+	val >>= shift;
+	val &= 7;	//we now have 3 bits per output
+	eitem = xlate[val];
+	if (eitem == 255) {
+		snd_BUG();
+		return 0;
+	}
+	return eitem;
+}
+
+static int put_route_val(ice1712_t *ice, unsigned int val, int shift)
+{
+	unsigned int old_val, nval;
+	int change;
+	static unsigned char xroute[8] = {
+		0, /* PCM */
+		2, /* PSDIN0 Left */
+		3, /* PSDIN0 Right */
+		6, /* SPDIN Left */
+		7, /* SPDIN Right */
+	};
+
+	nval = xroute[val % 5];
+	val = old_val = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
+	val &= ~(0x07 << shift);
+	val |= nval << shift;
+	change = val != old_val;
+	if (change)
+		outl(val, ICEMT1724(ice, ROUTE_PLAYBACK));
+	return change;
+}
+
+static int snd_vt1724_pro_route_analog_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int idx = kcontrol->id.index;
+	ucontrol->value.enumerated.item[0] = get_route_val(ice, analog_route_shift(idx));
+	return 0;
+}
+
+static int snd_vt1724_pro_route_analog_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int idx = kcontrol->id.index;
+	return put_route_val(ice, ucontrol->value.enumerated.item[0],
+			     analog_route_shift(idx));
+}
+
+static int snd_vt1724_pro_route_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int idx = kcontrol->id.index;
+	ucontrol->value.enumerated.item[0] = get_route_val(ice, digital_route_shift(idx));
+	return 0;
+}
+
+static int snd_vt1724_pro_route_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int idx = kcontrol->id.index;
+	return put_route_val(ice, ucontrol->value.enumerated.item[0],
+			     digital_route_shift(idx));
+}
+
+static snd_kcontrol_new_t snd_vt1724_mixer_pro_analog_route __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "H/W Playback Route",
+	.info = snd_vt1724_pro_route_info,
+	.get = snd_vt1724_pro_route_analog_get,
+	.put = snd_vt1724_pro_route_analog_put,
+};
+
+static snd_kcontrol_new_t snd_vt1724_mixer_pro_spdif_route __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC958 Playback Route",
+	.info = snd_vt1724_pro_route_info,
+	.get = snd_vt1724_pro_route_spdif_get,
+	.put = snd_vt1724_pro_route_spdif_put,
+};
+
+
+static int snd_vt1724_pro_peak_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 22; /* FIXME: for compatibility with ice1712... */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 255;
+	return 0;
+}
+
+static int snd_vt1724_pro_peak_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int idx;
+	
+	spin_lock_irq(&ice->reg_lock);
+	for (idx = 0; idx < 22; idx++) {
+		outb(idx, ICEMT1724(ice, MONITOR_PEAKINDEX));
+		ucontrol->value.integer.value[idx] = inb(ICEMT1724(ice, MONITOR_PEAKDATA));
+	}
+	spin_unlock_irq(&ice->reg_lock);
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_vt1724_mixer_pro_peak __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Multi Track Peak",
+	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info = snd_vt1724_pro_peak_info,
+	.get = snd_vt1724_pro_peak_get
+};
+
+/*
+ *
+ */
+
+static unsigned char __devinit snd_vt1724_read_i2c(ice1712_t *ice,
+						 unsigned char dev,
+						 unsigned char addr)
+{
+	long t = 0x10000;
+
+	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
+	outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
+	while (t-- > 0 && (inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY)) ;
+	return inb(ICEREG1724(ice, I2C_DATA));
+}
+
+static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice)
+{
+	int dev = 0xa0;		/* EEPROM device address */
+	unsigned int i;
+
+	if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) == 0) {
+		snd_printk("ICE1724 has not detected EEPROM\n");
+		return -EIO;
+	}
+	ice->eeprom.subvendor = (snd_vt1724_read_i2c(ice, dev, 0x00) << 0) |
+				(snd_vt1724_read_i2c(ice, dev, 0x01) << 8) | 
+				(snd_vt1724_read_i2c(ice, dev, 0x02) << 16) | 
+				(snd_vt1724_read_i2c(ice, dev, 0x03) << 24);
+	ice->eeprom.size = snd_vt1724_read_i2c(ice, dev, 0x04);
+	if (ice->eeprom.size > 32) {
+		snd_printk("invalid EEPROM (size = %i)\n", ice->eeprom.size);
+		return -EIO;
+	}
+	ice->eeprom.version = snd_vt1724_read_i2c(ice, dev, 0x05);
+	if (ice->eeprom.version != 2) {
+		snd_printk("invalid EEPROM version %i\n", ice->eeprom.version);
+		// return -EIO;
+	}
+	for (i = 0; i < ice->eeprom.size; i++)
+		ice->eeprom.data[i] = snd_vt1724_read_i2c(ice, dev, i + 6);
+
+	ice->eeprom.gpiomask = eeprom_triple(ice, ICE_EEP2_GPIO_MASK);
+	ice->eeprom.gpiostate = eeprom_triple(ice, ICE_EEP2_GPIO_STATE);
+	ice->eeprom.gpiodir = eeprom_triple(ice, ICE_EEP2_GPIO_DIR);
+
+	return 0;
+}
+
+
+
+static int __devinit snd_vt1724_chip_init(ice1712_t *ice)
+{
+	outb(VT1724_RESET , ICEREG1724(ice, CONTROL));
+	udelay(200);
+	outb(0, ICEREG1724(ice, CONTROL));
+	udelay(200);
+	outb(ice->eeprom.data[ICE_EEP2_SYSCONF], ICEREG1724(ice, SYS_CFG));
+	outb(ice->eeprom.data[ICE_EEP2_ACLINK], ICEREG1724(ice, AC97_CFG));
+	outb(ice->eeprom.data[ICE_EEP2_I2S], ICEREG1724(ice, I2S_FEATURES));
+	outb(ice->eeprom.data[ICE_EEP2_SPDIF], ICEREG1724(ice, SPDIF_CFG));
+
+	ice->gpio.write_mask = ice->eeprom.gpiomask;
+	ice->gpio.direction = ice->eeprom.gpiodir;
+	snd_vt1724_set_gpio_mask(ice, ice->eeprom.gpiomask);
+	snd_vt1724_set_gpio_dir(ice, ice->eeprom.gpiodir);
+	snd_vt1724_set_gpio_data(ice, ice->eeprom.gpiostate);
+
+	outb(0, ICEREG1724(ice, POWERDOWN));
+
+	return 0;
+}
+
+static int __devinit snd_vt1724_spdif_build_controls(ice1712_t *ice)
+{
+	int err;
+	unsigned int idx;
+	snd_kcontrol_t *kctl;
+
+	snd_assert(ice->pcm != NULL, return -EIO);
+
+	for (idx = 0; idx < 2; idx++) {
+		kctl = snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice);
+		if (kctl == NULL)
+			return -ENOMEM;
+		kctl->id.index = idx;
+		err = snd_ctl_add(ice->card, kctl);
+		if (err < 0)
+			return err;
+	}
+
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice));
+	if (err < 0)
+		return err;
+
+	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_default, ice));
+	if (err < 0)
+		return err;
+	kctl->id.device = ice->pcm->device;
+	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_maskc, ice));
+	if (err < 0)
+		return err;
+	kctl->id.device = ice->pcm->device;
+	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_maskp, ice));
+	if (err < 0)
+		return err;
+	kctl->id.device = ice->pcm->device;
+#if 0 /* use default only */
+	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_stream, ice));
+	if (err < 0)
+		return err;
+	kctl->id.device = ice->pcm->device;
+	ice->spdif.stream_ctl = kctl;
+#endif
+	return 0;
+}
+
+
+static int __devinit snd_vt1724_build_controls(ice1712_t *ice)
+{
+	unsigned int idx;
+	snd_kcontrol_t *kctl;
+	int err;
+
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_eeprom, ice));
+	if (err < 0)
+		return err;
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_pro_internal_clock, ice));
+	if (err < 0)
+		return err;
+
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_pro_rate_locking, ice));
+	if (err < 0)
+		return err;
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_pro_rate_reset, ice));
+	if (err < 0)
+		return err;
+
+	for (idx = 0; idx < ice->num_total_dacs; idx++) {
+		kctl = snd_ctl_new1(&snd_vt1724_mixer_pro_analog_route, ice);
+		if (kctl == NULL)
+			return -ENOMEM;
+		kctl->id.index = idx;
+		err = snd_ctl_add(ice->card, kctl);
+		if (err < 0)
+			return err;
+	}
+
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_peak, ice));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int snd_vt1724_free(ice1712_t *ice)
+{
+	if (ice->res_port == NULL)
+		goto __hw_end;
+	/* mask all interrupts */
+	outb(0xff, ICEMT1724(ice, DMA_INT_MASK));
+	outb(0xff, ICEREG1724(ice, IRQMASK));
+	/* --- */
+      __hw_end:
+	if (ice->irq >= 0) {
+		synchronize_irq(ice->irq);
+		free_irq(ice->irq, (void *) ice);
+	}
+	if (ice->res_port) {
+		release_resource(ice->res_port);
+		kfree_nocheck(ice->res_port);
+	}
+	if (ice->res_profi_port) {
+		release_resource(ice->res_profi_port);
+		kfree_nocheck(ice->res_profi_port);
+	}
+	if (ice->akm)
+		kfree(ice->akm);
+	snd_magic_kfree(ice);
+	return 0;
+}
+
+static int snd_vt1724_dev_free(snd_device_t *device)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, device->device_data, return -ENXIO);
+	return snd_vt1724_free(ice);
+}
+
+static int __devinit snd_vt1724_create(snd_card_t * card,
+				       struct pci_dev *pci,
+				       ice1712_t ** r_ice1712)
+{
+	ice1712_t *ice;
+	int err;
+	unsigned char mask;
+	static snd_device_ops_t ops = {
+		.dev_free =	snd_vt1724_dev_free,
+	};
+
+	*r_ice1712 = NULL;
+
+        /* enable PCI device */
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+	pci_set_dma_mask(pci, 0xffffffff); 
+
+	ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL);
+	if (ice == NULL)
+		return -ENOMEM;
+	ice->vt1724 = 1;
+	spin_lock_init(&ice->reg_lock);
+	init_MUTEX(&ice->gpio_mutex);
+	ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
+	ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
+	ice->gpio.set_data = snd_vt1724_set_gpio_data;
+	ice->gpio.get_data = snd_vt1724_get_gpio_data;
+	ice->card = card;
+	ice->pci = pci;
+	ice->irq = -1;
+	ice->port = pci_resource_start(pci, 0);
+	ice->profi_port = pci_resource_start(pci, 1);
+	pci_set_master(pci);
+	snd_vt1724_proc_init(ice);
+	synchronize_irq(pci->irq);
+
+	if ((ice->res_port = request_region(ice->port, 32, "ICE1724 - Controller")) == NULL) {
+		snd_vt1724_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->port, ice->port + 32 - 1);
+		return -EIO;
+	}
+
+	if ((ice->res_profi_port = request_region(ice->profi_port, 128, "ICE1724 - Professional")) == NULL) {
+		snd_vt1724_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->profi_port, ice->profi_port + 16 - 1);
+		return -EIO;
+	}
+		
+	if (request_irq(pci->irq, snd_vt1724_interrupt, SA_INTERRUPT|SA_SHIRQ, "ICE1724", (void *) ice)) {
+		snd_vt1724_free(ice);
+		snd_printk("unable to grab IRQ %d\n", pci->irq);
+		return -EIO;
+	}
+
+	ice->irq = pci->irq;
+
+	if (snd_vt1724_read_eeprom(ice) < 0) {
+		snd_vt1724_free(ice);
+		return -EIO;
+	}
+	if (snd_vt1724_chip_init(ice) < 0) {
+		snd_vt1724_free(ice);
+		return -EIO;
+	}
+
+	/* unmask used interrupts */
+	if (! (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401))
+		mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX;
+	else
+		mask = 0;
+	outb(mask, ICEREG1724(ice, IRQMASK));
+	/* don't handle FIFO overrun/underruns (just yet), since they cause machine lockups */
+	outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK));
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops)) < 0) {
+		snd_vt1724_free(ice);
+ 		return err;
+	}
+
+	*r_ice1712 = ice;
+	return 0;
+}
+
+
+/*
+ *
+ * Registration
+ *
+ */
+
+static struct snd_ice1712_card_info no_matched __devinitdata;
+
+static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+	snd_vt1724_revo_cards,
+	snd_vt1724_amp_cards, 
+	0,
+};
+
+
+static int __devinit snd_vt1724_probe(struct pci_dev *pci,
+				      const struct pci_device_id *pci_id)
+{
+	static int dev;
+	snd_card_t *card;
+	ice1712_t *ice;
+	int pcm_dev = 0, err;
+	struct snd_ice1712_card_info **tbl, *c;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	strcpy(card->driver, "ICE1724");
+	strcpy(card->shortname, "ICEnsemble ICE1724");
+	
+	if ((err = snd_vt1724_create(card, pci, &ice)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	for (tbl = card_tables; *tbl; tbl++) {
+		for (c = *tbl; c->subvendor; c++) {
+			if (c->subvendor == ice->eeprom.subvendor) {
+				strcpy(card->shortname, c->name);
+				if (c->chip_init) {
+					if ((err = c->chip_init(ice)) < 0) {
+						snd_card_free(card);
+						return err;
+					}
+				}
+				goto __found;
+			}
+		}
+	}
+	c = &no_matched;
+ __found:
+
+	if ((err = snd_vt1724_pcm_profi(ice, pcm_dev++)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	
+	if ((err = snd_vt1724_pcm_spdif(ice, pcm_dev++)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	
+	if ((err = snd_vt1724_ac97_mixer(ice)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	if ((err = snd_vt1724_build_controls(ice)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	if (ice->pcm) { /* has SPDIF I/O */
+		if ((err = snd_vt1724_spdif_build_controls(ice)) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+	}
+
+	if (c->build_controls) {
+		if ((err = c->build_controls(ice)) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+	}
+
+	if (! c->no_mpu401) {
+		if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
+			if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
+						       ICEREG1724(ice, MPU_CTRL), 1,
+						       ice->irq, 0,
+						       &ice->rmidi[0])) < 0) {
+				snd_card_free(card);
+				return err;
+			}
+		}
+	}
+
+	sprintf(card->longname, "%s at 0x%lx, irq %i",
+		card->shortname, ice->port, ice->irq);
+
+	if ((err = snd_card_register(card)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	pci_set_drvdata(pci, card);
+	dev++;
+	return 0;
+}
+
+static void __devexit snd_vt1724_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+	.name = "ICE1724",
+	.id_table = snd_vt1724_ids,
+	.probe = snd_vt1724_probe,
+	.remove = __devexit_p(snd_vt1724_remove),
+};
+
+static int __init alsa_card_ice1724_init(void)
+{
+	int err;
+
+	if ((err = pci_module_init(&driver)) < 0) {
+#ifdef MODULE
+		printk(KERN_ERR "ICE1724 soundcard not found or device busy\n");
+#endif
+		return err;
+	}
+	return 0;
+}
+
+static void __exit alsa_card_ice1724_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_ice1724_init)
+module_exit(alsa_card_ice1724_exit)
+
+#ifndef MODULE
+
+/* format is: snd-ice1724=enable,index,id */
+
+static int __init alsa_card_ice1724_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&enable[nr_dev]) == 2 &&
+	       get_option(&str,&index[nr_dev]) == 2 &&
+	       get_id(&str,&id[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-ice1724=", alsa_card_ice1724_setup);
+
+#endif /* ifndef MODULE */
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/revo.c linux-2.5.65-bk2/sound/pci/ice1712/revo.c
--- linux-2.5.65-bk1/sound/pci/ice1712/revo.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/sound/pci/ice1712/revo.c	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,169 @@
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for M-Audio Revolution 7.1
+ *
+ *	Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "revo.h"
+
+/*
+ * change the rate of envy24HT, AK4355 and AK4381
+ */
+static void revo_set_rate_val(akm4xxx_t *ak, unsigned int rate)
+{
+	unsigned char old, tmp, dfs;
+	int reg, shift;
+
+	if (rate == 0)	/* no hint - S/PDIF input is master, simply return */
+		return;
+
+	/* adjust DFS on codecs */
+	if (rate > 96000)
+		dfs = 2;
+	else if (rate > 48000)
+		dfs = 1;
+	else
+		dfs = 0;
+
+	if (ak->type == SND_AK4355) {
+		reg = 2;
+		shift = 4;
+	} else {
+		reg = 1;
+		shift = 3;
+	}
+	tmp = ak->images[0][reg];
+	old = (tmp >> shift) & 0x03;
+	if (old == dfs)
+		return;
+
+	/* reset DFS */
+	snd_ice1712_akm4xxx_reset(ak, 1);
+	tmp = ak->images[0][reg];
+	tmp &= ~(0x03 << shift);
+	tmp |= dfs << shift;
+	snd_ice1712_akm4xxx_write(ak, 0, reg, tmp);
+	snd_ice1712_akm4xxx_reset(ak, 0);
+}
+
+/*
+ * initialize the chips on M-Audio Revolution cards
+ */
+
+static akm4xxx_t akm_revo_front __devinitdata = {
+	.type = SND_AK4381,
+	.num_dacs = 2,
+	.caddr = 1,
+	.cif = 0,
+	.data_mask = VT1724_REVO_CDOUT,
+	.clk_mask = VT1724_REVO_CCLK,
+	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+	.cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
+	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+	.add_flags = VT1724_REVO_CCLK, /* high at init */
+	.mask_flags = 0,
+	.ops = {
+		.set_rate_val = revo_set_rate_val
+	}
+};
+
+static akm4xxx_t akm_revo_surround __devinitdata = {
+	.type = SND_AK4355,
+	.idx_offset = 1,
+	.num_dacs = 6,
+	.caddr = 3,
+	.cif = 0,
+	.data_mask = VT1724_REVO_CDOUT,
+	.clk_mask = VT1724_REVO_CCLK,
+	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+	.cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+	.add_flags = VT1724_REVO_CCLK, /* high at init */
+	.mask_flags = 0,
+	.ops = {
+		.set_rate_val = revo_set_rate_val
+	}
+};
+
+static int __devinit revo_init(ice1712_t *ice)
+{
+	akm4xxx_t *ak;
+
+	/* determine I2C, DACs and ADCs */
+	switch (ice->eeprom.subvendor) {
+	case VT1724_SUBDEVICE_REVOLUTION71:
+		ice->num_total_dacs = 8;
+		break;
+	default:
+		snd_BUG();
+		return -EINVAL;
+	}
+
+	/* second stage of initialization, analog parts and others */
+	ak = ice->akm = kmalloc(sizeof(akm4xxx_t) * 2, GFP_KERNEL);
+	if (! ak)
+		return -ENOMEM;
+	ice->akm_codecs = 2;
+	switch (ice->eeprom.subvendor) {
+	case VT1724_SUBDEVICE_REVOLUTION71:
+		snd_ice1712_akm4xxx_init(ak, &akm_revo_front, ice);
+		snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, ice);
+		/* unmute all codecs */
+		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int __devinit revo_add_controls(ice1712_t *ice)
+{
+	int err;
+
+	switch (ice->eeprom.subvendor) {
+	case VT1724_SUBDEVICE_REVOLUTION71:
+		err = snd_ice1712_akm4xxx_build_controls(ice);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
+	{
+		VT1724_SUBDEVICE_REVOLUTION71,
+		"M Audio Revolution-7.1",
+		revo_init,
+		revo_add_controls,
+	},
+	{ } /* terminator */
+};
diff -urN linux-2.5.65-bk1/sound/pci/ice1712/revo.h linux-2.5.65-bk2/sound/pci/ice1712/revo.h
--- linux-2.5.65-bk1/sound/pci/ice1712/revo.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.65-bk2/sound/pci/ice1712/revo.h	Mon Mar 31 12:39:51 2003
@@ -0,0 +1,48 @@
+#ifndef __SOUND_REVO_H
+#define __SOUND_REVO_H
+
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for M-Audio Revolution 7.1
+ *
+ *	Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#define REVO_DEVICE_DESC \
+		"{MidiMan M Audio,Revolution 7.1},"
+
+#define VT1724_SUBDEVICE_REVOLUTION71	0x12143036
+
+/* entry point */
+extern struct snd_ice1712_card_info snd_vt1724_revo_cards[];
+
+
+/*
+ *  MidiMan M-Audio Revolution GPIO definitions
+ */
+
+#define VT1724_REVO_CCLK	0x02
+#define VT1724_REVO_CDIN	0x04	/* not used */
+#define VT1724_REVO_CDOUT	0x08
+#define VT1724_REVO_CS0		0x10	/* not used */
+#define VT1724_REVO_CS1		0x20	/* front AKM4381 chipselect */
+#define VT1724_REVO_CS2		0x40	/* surround AKM4355 chipselect */
+#define VT1724_REVO_MUTE	(1<<22)	/* 0 = all mute, 1 = normal operation */
+
+#endif /* __SOUND_REVO_H */
diff -urN linux-2.5.65-bk1/sound/pci/intel8x0.c linux-2.5.65-bk2/sound/pci/intel8x0.c
--- linux-2.5.65-bk1/sound/pci/intel8x0.c	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/sound/pci/intel8x0.c	Mon Mar 31 12:39:51 2003
@@ -50,6 +50,7 @@
 		"{Intel,82801BA-ICH2},"
 		"{Intel,82801CA-ICH3},"
 		"{Intel,82801DB-ICH4},"
+		"{Intel,ICH5},"
 		"{Intel,MX440},"
 		"{SiS,SI7012},"
 		"{NVidia,NForce Audio},"
@@ -122,6 +123,9 @@
 #ifndef PCI_DEVICE_ID_INTEL_ICH4
 #define PCI_DEVICE_ID_INTEL_ICH4	0x24c5
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH5
+#define PCI_DEVICE_ID_INTEL_ICH5	0x24d5
+#endif
 #ifndef PCI_DEVICE_ID_SI_7012
 #define PCI_DEVICE_ID_SI_7012		0x7012
 #endif
@@ -191,6 +195,10 @@
 #define   ICH_PCM_6		0x00200000	/* 6 channels (not all chips) */
 #define   ICH_PCM_4		0x00100000	/* 4 channels (not all chips) */
 #define   ICH_PCM_2		0x00000000	/* 2 channels (stereo) */
+#define   ICH_SIS_PCM_246_MASK	0x000000c0	/* 6 channels (SIS7012) */
+#define   ICH_SIS_PCM_6		0x00000080	/* 6 channels (SIS7012) */
+#define   ICH_SIS_PCM_4		0x00000040	/* 4 channels (SIS7012) */
+#define   ICH_SIS_PCM_2		0x00000000	/* 2 channels (SIS7012) */
 #define   ICH_SRIE		0x00000020	/* secondary resume interrupt enable */
 #define   ICH_PRIE		0x00000010	/* primary resume interrupt enable */
 #define   ICH_ACLINK		0x00000008	/* AClink shut off */
@@ -385,6 +393,7 @@
 	{ 0x8086, 0x2445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 82801BA */
 	{ 0x8086, 0x2485, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* ICH3 */
 	{ 0x8086, 0x24c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH4 */
+	{ 0x8086, 0x24d5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH5 */
 	{ 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 440MX */
 	{ 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },	/* SI7012 */
 	{ 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* NFORCE */
@@ -818,11 +827,20 @@
 
 static void snd_intel8x0_setup_multi_channels(intel8x0_t *chip, int channels)
 {
-	unsigned int cnt = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_246_MASK;
-	if (chip->multi4 && channels == 4)
-		cnt |= ICH_PCM_4;
-	else if (chip->multi6 && channels == 6)
-		cnt |= ICH_PCM_6;
+	unsigned int cnt = igetdword(chip, ICHREG(GLOB_CNT));
+	if (chip->device_type == DEVICE_SIS) {
+		cnt &= ~ICH_SIS_PCM_246_MASK;
+		if (chip->multi4 && channels == 4)
+			cnt |= ICH_SIS_PCM_4;
+		else if (chip->multi6 && channels == 6)
+			cnt |= ICH_SIS_PCM_6;
+	} else {
+		cnt &= ~ICH_PCM_246_MASK;
+		if (chip->multi4 && channels == 4)
+			cnt |= ICH_PCM_4;
+		else if (chip->multi6 && channels == 6)
+			cnt |= ICH_PCM_6;
+	}
 	iputdword(chip, ICHREG(GLOB_CNT), cnt);
 }
 
@@ -1508,12 +1526,17 @@
 	{ ALID_SPDIFIN, { 0, 0, 0 }, -1 },
 };
 
+static struct ac97_quirk ac97_quirks[] = {
+	{ 0x1028, 0x0126, "Dell Optiplex GX260", AC97_TUNE_HP_ONLY },
+	{ 0x1734, 0x0088, "Fujisu-Siemens D1522", AC97_TUNE_HP_ONLY },
+	{ } /* terminator */
+};
 
 static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
 {
 	ac97_t ac97, *x97;
 	ichdev_t *ichdev;
-	int err, i, channels = 2, codecs;
+	int err, i, num, channels = 2, codecs, _codecs;
 	unsigned int glob_sta = 0;
 
 	for (i = 0; i <= ICHD_LAST; i++) {
@@ -1589,6 +1612,7 @@
 	if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0)
 		return err;
 	chip->ac97[0] = x97;
+	snd_ac97_tune_hardware(chip->ac97[0], chip->pci, ac97_quirks);
 	chip->ichd[ICHD_PCMOUT].ac97 = x97;
 	chip->ichd[ICHD_PCMIN].ac97 = x97;
 	if (x97->ext_id & AC97_EI_VRM)
@@ -1604,20 +1628,20 @@
 		snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 0);
 	/* AnalogDevices CNR boards uses special codec chaining */
 	/* skip standard test method for secondary codecs in this case */
-	if (x97->flags & AC97_AD_MULTI) {
+	if (x97->flags & AC97_AD_MULTI)
 		codecs = 1;
-		goto __skip_secondary;
-	}
 	if (codecs < 2)
 		goto __skip_secondary;
-	for (i = 1; i < codecs; i++) {
-		ac97.num = i;
+	for (i = 1, num = 1, _codecs = codecs; num < _codecs; num++) {
+		ac97.num = num;
 		if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0) {
 			snd_printk("Unable to initialize codec #%i [device = %i, GLOB_STA = 0x%x]\n", i, chip->device_type, glob_sta);
-			codecs = i;
-			break;
+			codecs--;
+			continue;
 		}
-		chip->ac97[i] = x97;
+		chip->ac97[i++] = x97;
+		if (!ac97_is_audio(x97))
+			continue;
 		switch (chip->device_type) {
 		case DEVICE_INTEL_ICH4:
 			if (chip->ichd[ICHD_PCM2IN].ac97 == NULL)
@@ -1656,14 +1680,16 @@
 		}
 		iputbyte(chip, ICHREG(SDM), tmp);
 	}
-      	for (i = 0; i < 3; i++) {
-		if ((x97 = chip->ac97[i]) == NULL)
+      	for (i = 0; i < codecs; i++) {
+		x97 = chip->ac97[i];
+		if (!ac97_is_audio(x97))
 			continue;
 		if (x97->scaps & AC97_SCAP_SURROUND_DAC)
 			chip->multi4 = 1;
 	}
-      	for (i = 0; i < 3 && chip->multi4; i++) {
-		if ((x97 = chip->ac97[i]) == NULL)
+      	for (i = 0; i < codecs && chip->multi4; i++) {
+		x97 = chip->ac97[i];
+		if (!ac97_is_audio(x97))
 			continue;
 		if (x97->scaps & AC97_SCAP_CENTER_LFE_DAC)
 			chip->multi6 = 1;
@@ -1674,7 +1700,10 @@
 		if (chip->multi4)
 			goto __6ch;
 		for ( ; i < codecs; i++) {
-			if (ac97_is_rev22(x97 = chip->ac97[i])) {
+			x97 = chip->ac97[i];
+			if (!ac97_is_audio(x97))
+				continue;
+			if (ac97_is_rev22(x97)) {
 				snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 1);
 				chip->multi4 = 1;
 				break;
@@ -1682,7 +1711,10 @@
 		}
 	      __6ch:
 		for ( ; i < codecs && chip->multi4; i++) {
-			if (ac97_is_rev22(x97 = chip->ac97[i])) {
+			x97 = chip->ac97[i];
+			if (!ac97_is_audio(x97))
+				continue;
+			if (ac97_is_rev22(x97)) {
 				snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 2);
 				chip->multi6 = 1;
 				break;
@@ -1691,7 +1723,10 @@
 		/* ok, some older codecs might support only AMAP */
 		if (!chip->multi4) {
 			for (i = 1; i < codecs; i++) {
-				if (ac97_can_amap(x97 = chip->ac97[i])) {
+				x97 = chip->ac97[i];
+				if (!ac97_is_audio(x97))
+					continue;
+				if (ac97_can_amap(x97)) {
 					if (x97->addr == 1) {
 						chip->multi4 = 1;
 						break;
@@ -1699,7 +1734,9 @@
 				}
 			}
 			for ( ; i < codecs && chip->multi4; i++) {
-				if (ac97_can_amap(x97 = chip->ac97[i])) {
+				if (!ac97_is_audio(x97))
+					continue;
+				if (ac97_can_amap(x97)) {
 					if (x97->addr == 2) {
 						chip->multi6 = 1;
 						break;
@@ -1741,7 +1778,7 @@
 
 static int snd_intel8x0_ich_chip_init(intel8x0_t *chip)
 {
-	unsigned long end_time;
+	signed long end_time;
 	unsigned int cnt, status, nstatus;
 	
 	/* put logic to right state */
@@ -2302,6 +2339,7 @@
 	{ PCI_DEVICE_ID_INTEL_440MX, "Intel 440MX" },
 	{ PCI_DEVICE_ID_INTEL_ICH3, "Intel 82801CA-ICH3" },
 	{ PCI_DEVICE_ID_INTEL_ICH4, "Intel 82801DB-ICH4" },
+	{ PCI_DEVICE_ID_INTEL_ICH5, "Intel ICH5" },
 	{ PCI_DEVICE_ID_SI_7012, "SiS SI7012" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia NForce" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia NForce2" },
@@ -2433,12 +2471,12 @@
 
 static struct pci_driver driver = {
 	.name = "Intel ICH",
-	id_table: snd_intel8x0_ids,
-	probe: snd_intel8x0_probe,
-	remove: __devexit_p(snd_intel8x0_remove),
+	.id_table = snd_intel8x0_ids,
+	.probe = snd_intel8x0_probe,
+	.remove = __devexit_p(snd_intel8x0_remove),
 #ifdef CONFIG_PM
-	suspend: snd_intel8x0_suspend,
-	resume: snd_intel8x0_resume,
+	.suspend = snd_intel8x0_suspend,
+	.resume = snd_intel8x0_resume,
 #endif
 };
 
diff -urN linux-2.5.65-bk1/sound/pci/korg1212/korg1212.c linux-2.5.65-bk2/sound/pci/korg1212/korg1212.c
--- linux-2.5.65-bk1/sound/pci/korg1212/korg1212.c	Mon Mar 17 13:43:38 2003
+++ linux-2.5.65-bk2/sound/pci/korg1212/korg1212.c	Mon Mar 31 12:39:51 2003
@@ -42,6 +42,7 @@
 // ----------------------------------------------------------------------------
 #define K1212_DEBUG_LEVEL		0
 #define K1212_DEBUG_PRINTK		printk
+//#define K1212_DEBUG_PRINTK(x...)	printk("<0>" x)
 
 // ----------------------------------------------------------------------------
 // Record/Play Buffer Allocation Method. If K1212_LARGEALLOC is defined all 
@@ -178,13 +179,21 @@
 #define kAudioChannels		(k16BitChannels + k32BitChannels)
 #define kPlayBufferFrames	1024
 
-#define K1212_CHANNELS     	16
+#define K1212_ANALOG_CHANNELS	2
+#define K1212_SPDIF_CHANNELS	2
+#define K1212_ADAT_CHANNELS	8
+#define K1212_CHANNELS		(K1212_ADAT_CHANNELS + K1212_ANALOG_CHANNELS)
+#define K1212_MIN_CHANNELS	1
+#define K1212_MAX_CHANNELS	K1212_CHANNELS
 #define K1212_FRAME_SIZE        (sizeof(KorgAudioFrame))
 #define K1212_MAX_SAMPLES	(kPlayBufferFrames*kNumBuffers)
-#define K1212_PERIODS		(K1212_BUF_SIZE/K1212_BLOCK_SIZE)
-#define K1212_PERIOD_BYTES	(K1212_BLOCK_SIZE)
-#define K1212_BLOCK_SIZE        (K1212_FRAME_SIZE*kPlayBufferFrames)
-#define K1212_BUF_SIZE          (K1212_BLOCK_SIZE*kNumBuffers)
+#define K1212_PERIODS		(kNumBuffers)
+#define K1212_PERIOD_BYTES	(K1212_FRAME_SIZE*kPlayBufferFrames)
+#define K1212_BUF_SIZE          (K1212_PERIOD_BYTES*kNumBuffers)
+#define K1212_ANALOG_BUF_SIZE	(K1212_ANALOG_CHANNELS * 2 * kPlayBufferFrames * kNumBuffers)
+#define K1212_SPDIF_BUF_SIZE	(K1212_SPDIF_CHANNELS * 3 * kPlayBufferFrames * kNumBuffers)
+#define K1212_ADAT_BUF_SIZE	(K1212_ADAT_CHANNELS * 2 * kPlayBufferFrames * kNumBuffers)
+#define K1212_MAX_BUF_SIZE	(K1212_ANALOG_BUF_SIZE + K1212_ADAT_BUF_SIZE)
 
 #define k1212MinADCSens     0x7f
 #define k1212MaxADCSens     0x00
@@ -314,9 +323,9 @@
 } SensBits;
 
 struct _snd_korg1212 {
-        struct pci_dev *pci;
         snd_card_t *card;
-        snd_pcm_t *pcm16;
+        struct pci_dev *pci;
+        snd_pcm_t *pcm;
         int irq;
 
         spinlock_t    lock;
@@ -362,9 +371,9 @@
         u16 * sensRegPtr;	     // address of the sensitivity setting register
         u32 * idRegPtr;		     // address of the device and vendor ID registers
 
-
         size_t periodsize;
-        size_t currentBuffer;
+	int channels;
+        int currentBuffer;
 
         snd_pcm_substream_t *playback_substream;
         snd_pcm_substream_t *capture_substream;
@@ -383,6 +392,11 @@
 
         u16 leftADCInSens;           // ADC left channel input sensitivity
         u16 rightADCInSens;          // ADC right channel input sensitivity
+
+	int opencnt;			// Open/Close count
+	int setcnt;			// SetupForPlay count
+	int playcnt;			// TriggerPlay count
+
 };
 
 MODULE_DESCRIPTION("korg1212");
@@ -465,7 +479,6 @@
 
 static snd_korg1212rc rc;
 
-
 MODULE_DEVICE_TABLE(pci, snd_korg1212_ids);
 
 typedef union swap_u32 { unsigned char c[4]; u32 i; } swap_u32;
@@ -521,11 +534,6 @@
 
 #endif /* not used */
 
-void TickDelay(int time)
-{
-        udelay(time);
-}
-
 #define SetBitInWord(theWord,bitPosition)       (*theWord) |= (0x0001 << bitPosition)
 #define SetBitInDWord(theWord,bitPosition)      (*theWord) |= (0x00000001 << bitPosition)
 #define ClearBitInWord(theWord,bitPosition)     (*theWord) &= ~(0x0001 << bitPosition)
@@ -536,76 +544,95 @@
 {
         u32 retryCount;
         u16 mailBox3Lo;
+	snd_korg1212rc rc = K1212_CMDRET_Success;
 
-        if (korg1212->outDoorbellPtr) {
-#if K1212_DEBUG_LEVEL > 0
-		K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- 0x%08x 0x%08x [%s]\n", doorbellVal, mailBox0Val, stateName[korg1212->cardState]);
+        if (!korg1212->outDoorbellPtr) {
+#if K1212_DEBUG_LEVEL > 1
+		K1212_DEBUG_PRINTK("K1212_DEBUG: CardUninitialized\n");
 #endif
-                for (retryCount = 0; retryCount < MAX_COMMAND_RETRIES; retryCount++) {
+                return K1212_CMDRET_CardUninitialized;
+	}
 
-                        writel(mailBox3Val, korg1212->mailbox3Ptr);
-                        writel(mailBox2Val, korg1212->mailbox2Ptr);
-                        writel(mailBox1Val, korg1212->mailbox1Ptr);
-                        writel(mailBox0Val, korg1212->mailbox0Ptr);
-                        writel(doorbellVal, korg1212->outDoorbellPtr);  // interrupt the card
-
-                        // --------------------------------------------------------------
-                        // the reboot command will not give an acknowledgement.
-                        // --------------------------------------------------------------
-                        switch (doorbellVal) {
-                                case K1212_DB_RebootCard:
-                                case K1212_DB_BootFromDSPPage4:
-                                case K1212_DB_StartDSPDownload:
-                                        return K1212_CMDRET_Success;
-                                default:
-                                        break;
-                        }
+#if K1212_DEBUG_LEVEL > 0
+	K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- 0x%08x 0x%08x [%s]\n", doorbellVal, mailBox0Val, stateName[korg1212->cardState]);
+#endif
+        for (retryCount = 0; retryCount < MAX_COMMAND_RETRIES; retryCount++) {
+		writel(mailBox3Val, korg1212->mailbox3Ptr);
+                writel(mailBox2Val, korg1212->mailbox2Ptr);
+                writel(mailBox1Val, korg1212->mailbox1Ptr);
+                writel(mailBox0Val, korg1212->mailbox0Ptr);
+                writel(doorbellVal, korg1212->outDoorbellPtr);  // interrupt the card
+
+                // --------------------------------------------------------------
+                // the reboot command will not give an acknowledgement.
+                // --------------------------------------------------------------
+                if ( doorbellVal == K1212_DB_RebootCard ||
+                	doorbellVal == K1212_DB_BootFromDSPPage4 ||
+                        doorbellVal == K1212_DB_StartDSPDownload ) {
+                        rc = K1212_CMDRET_Success;
+                        break;
+                }
 
-                        // --------------------------------------------------------------
-                        // See if the card acknowledged the command.  Wait a bit, then
-                        // read in the low word of mailbox3.  If the MSB is set and the
-                        // low byte is equal to the doorbell value, then it ack'd.
-                        // --------------------------------------------------------------
-                        TickDelay(COMMAND_ACK_DELAY);
-                        mailBox3Lo = readl(korg1212->mailbox3Ptr);
-                        if (mailBox3Lo & COMMAND_ACK_MASK) {
-                                if ((mailBox3Lo & DOORBELL_VAL_MASK) == (doorbellVal & DOORBELL_VAL_MASK)) {
-                                        korg1212->cmdRetryCount += retryCount;
-                                        return K1212_CMDRET_Success;
-                                }
+                // --------------------------------------------------------------
+                // See if the card acknowledged the command.  Wait a bit, then
+                // read in the low word of mailbox3.  If the MSB is set and the
+                // low byte is equal to the doorbell value, then it ack'd.
+                // --------------------------------------------------------------
+                udelay(COMMAND_ACK_DELAY);
+                mailBox3Lo = readl(korg1212->mailbox3Ptr);
+                if (mailBox3Lo & COMMAND_ACK_MASK) {
+                	if ((mailBox3Lo & DOORBELL_VAL_MASK) == (doorbellVal & DOORBELL_VAL_MASK)) {
+#if K1212_DEBUG_LEVEL > 1
+				K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- Success\n");
+#endif
+                                rc = K1212_CMDRET_Success;
+				break;
                         }
                 }
-                korg1212->cmdRetryCount += retryCount;
-                return K1212_CMDRET_NoAckFromCard;
-        } else {
-                return K1212_CMDRET_CardUninitialized;
-        }
+	}
+        korg1212->cmdRetryCount += retryCount;
+
+	if (retryCount >= MAX_COMMAND_RETRIES) {
+#if K1212_DEBUG_LEVEL > 1
+		K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- NoAckFromCard\n");
+#endif
+        	rc = K1212_CMDRET_NoAckFromCard;
+	}
+
+	return rc;
 }
 
 static void snd_korg1212_WaitForCardStopAck(korg1212_t *korg1212)
 {
-        unsigned long endtime = jiffies + 20 * HZ;
+        u32 endtime = jiffies + 2 * HZ;
 
 #if K1212_DEBUG_LEVEL > 0
-        K1212_DEBUG_PRINTK("K1212_DEBUG: WaitForCardStopAck [%s]\n", stateName[korg1212->cardState]);
+        K1212_DEBUG_PRINTK("K1212_DEBUG: WaitForCardStopAck.in [%s] %lu %lu\n", stateName[korg1212->cardState], jiffies, korg1212->inIRQ);
 #endif
 
         if (korg1212->inIRQ)
                 return;
 
         do {
-                if (readl(&korg1212->sharedBufferPtr->cardCommand) == 0)
+                if (readl(&korg1212->sharedBufferPtr->cardCommand) == 0) {
+#if K1212_DEBUG_LEVEL > 0
+        		K1212_DEBUG_PRINTK("K1212_DEBUG: WaitForCardStopAck.out [%s] %lu %lu\n", stateName[korg1212->cardState], jiffies, korg1212->inIRQ);
+#endif
                         return;
+		}
                 if (!korg1212->inIRQ)
                         schedule();
         } while (time_before(jiffies, endtime));
 
+#if K1212_DEBUG_LEVEL > 0
+        K1212_DEBUG_PRINTK("K1212_DEBUG: WaitForCardStopAck.out TO [%s] %lu %lu\n", stateName[korg1212->cardState], jiffies, korg1212->inIRQ);
+#endif
         writel(0, &korg1212->sharedBufferPtr->cardCommand);
 }
 
 static void snd_korg1212_TurnOnIdleMonitor(korg1212_t *korg1212)
 {
-        TickDelay(INTERCOMMAND_DELAY);
+        udelay(INTERCOMMAND_DELAY);
         korg1212->idleMonitorOn = 1;
         rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
                         K1212_MODE_MonitorOn, 0, 0, 0);
@@ -641,18 +668,22 @@
 static int snd_korg1212_OpenCard(korg1212_t * korg1212)
 {
 #if K1212_DEBUG_LEVEL > 0
-	K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s]\n", stateName[korg1212->cardState]);
+	K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt);
 #endif
-        snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
+        if (korg1212->opencnt++ == 0)
+		snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
         return 1;
 }
 
 static int snd_korg1212_CloseCard(korg1212_t * korg1212)
 {
 #if K1212_DEBUG_LEVEL > 0
-	K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s]\n", stateName[korg1212->cardState]);
+	K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt);
 #endif
 
+	if (--(korg1212->opencnt))
+		return 0;
+
         if (korg1212->cardState == K1212_STATE_SETUP) {
                 rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
                                 K1212_MODE_StopPlay, 0, 0, 0);
@@ -676,9 +707,12 @@
 static int snd_korg1212_SetupForPlay(korg1212_t * korg1212)
 {
 #if K1212_DEBUG_LEVEL > 0
-	K1212_DEBUG_PRINTK("K1212_DEBUG: SetupForPlay [%s]\n", stateName[korg1212->cardState]);
+	K1212_DEBUG_PRINTK("K1212_DEBUG: SetupForPlay [%s] %d\n", stateName[korg1212->cardState], korg1212->setcnt);
 #endif
 
+        if (korg1212->setcnt++)
+		return 0;
+
         snd_korg1212_setCardState(korg1212, K1212_STATE_SETUP);
         rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
                                         K1212_MODE_SetupPlay, 0, 0, 0);
@@ -687,17 +721,20 @@
 	if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: SetupForPlay - RC = %d [%s]\n", rc, stateName[korg1212->cardState]);
 #endif
         if (rc != K1212_CMDRET_Success) {
-                return 0;
+                return 1;
         }
-        return 1;
+        return 0;
 }
 
 static int snd_korg1212_TriggerPlay(korg1212_t * korg1212)
 {
 #if K1212_DEBUG_LEVEL > 0
-	K1212_DEBUG_PRINTK("K1212_DEBUG: TriggerPlay [%s]\n", stateName[korg1212->cardState]);
+	K1212_DEBUG_PRINTK("K1212_DEBUG: TriggerPlay [%s] %d\n", stateName[korg1212->cardState], korg1212->playcnt);
 #endif
 
+        if (korg1212->playcnt++)
+		return 0;
+
         snd_korg1212_setCardState(korg1212, K1212_STATE_PLAYING);
         rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_TriggerPlay, 0, 0, 0, 0);
 
@@ -706,23 +743,28 @@
 #endif
 
         if (rc != K1212_CMDRET_Success) {
-                return 0;
+                return 1;
         }
-        return 1;
+        return 0;
 }
 
 static int snd_korg1212_StopPlay(korg1212_t * korg1212)
 {
 #if K1212_DEBUG_LEVEL > 0
-	K1212_DEBUG_PRINTK("K1212_DEBUG: StopPlay [%s]\n", stateName[korg1212->cardState]);
+	K1212_DEBUG_PRINTK("K1212_DEBUG: StopPlay [%s] %d\n", stateName[korg1212->cardState], korg1212->playcnt);
 #endif
 
+        if (--(korg1212->playcnt)) 
+		return 0;
+
+	korg1212->setcnt = 0;
+
         if (korg1212->cardState != K1212_STATE_ERRORSTOP) {
                 writel(0xffffffff, &korg1212->sharedBufferPtr->cardCommand);
                 snd_korg1212_WaitForCardStopAck(korg1212);
         }
         snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
-        return 1;
+        return 0;
 }
 
 static void snd_korg1212_EnableCardInterrupts(korg1212_t * korg1212)
@@ -802,7 +844,7 @@
         korg1212->clkSrcRate = parm;
         korg1212->clkRate = rate;
 
-	TickDelay(INTERCOMMAND_DELAY);
+	udelay(INTERCOMMAND_DELAY);
 	rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SetClockSourceRate,
 					  ClockSourceSelector[korg1212->clkSrcRate],
 					  0, 0, 0);
@@ -869,7 +911,7 @@
         // flag.  Also, clear out mailbox 3, so we don't lockup.
         // ----------------------------------------------------------------------------
         writel(0, korg1212->mailbox3Ptr);
-        TickDelay(LOADSHIFT_DELAY);
+        udelay(LOADSHIFT_DELAY);
 
         // ----------------------------------------------------------------------------
         // determine whether we are running a 48K or 44.1K clock.  This info is used
@@ -910,7 +952,7 @@
                 ClearBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS);
                 ClearBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
                 writew(controlValue, korg1212->sensRegPtr);                          // load/shift goes low
-                TickDelay(LOADSHIFT_DELAY);
+                udelay(LOADSHIFT_DELAY);
 
                 for (bitPosition = 15; bitPosition >= 0; bitPosition--) {       // for all the bits
                         if (channel == 0) {
@@ -929,10 +971,10 @@
 
                         ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
                         writew(controlValue, korg1212->sensRegPtr);                       // clock goes low
-                        TickDelay(SENSCLKPULSE_WIDTH);
+                        udelay(SENSCLKPULSE_WIDTH);
                         SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
                         writew(controlValue, korg1212->sensRegPtr);                       // clock goes high
-                        TickDelay(SENSCLKPULSE_WIDTH);
+                        udelay(SENSCLKPULSE_WIDTH);
                 }
 
                 // ----------------------------------------------------------------------------
@@ -943,19 +985,19 @@
                 ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
                 SetBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS);
                 writew(controlValue, korg1212->sensRegPtr);                   // load shift goes high - clk low
-                TickDelay(SENSCLKPULSE_WIDTH);
+                udelay(SENSCLKPULSE_WIDTH);
 
                 if (clkIs48K)
                         SetBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
 
                 writew(controlValue, korg1212->sensRegPtr);                   // set/clear data bit
-                TickDelay(ONE_RTC_TICK);
+                udelay(ONE_RTC_TICK);
                 SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
                 writew(controlValue, korg1212->sensRegPtr);                   // clock goes high
-                TickDelay(SENSCLKPULSE_WIDTH);
+                udelay(SENSCLKPULSE_WIDTH);
                 ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
                 writew(controlValue, korg1212->sensRegPtr);                   // clock goes low
-                TickDelay(SENSCLKPULSE_WIDTH);
+                udelay(SENSCLKPULSE_WIDTH);
         }
 
         // ----------------------------------------------------------------------------
@@ -963,7 +1005,7 @@
         // Also, if the card was in monitor mode, restore it.
         // ----------------------------------------------------------------------------
         for (count = 0; count < 10; count++)
-                TickDelay(SENSCLKPULSE_WIDTH);
+                udelay(SENSCLKPULSE_WIDTH);
 
         if (monModeSet) {
                 rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
@@ -1011,7 +1053,7 @@
 	if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: Configure Buffer Memory - RC = %d [%s]\n", rc, stateName[korg1212->cardState]);
 #endif
 
-        TickDelay(INTERCOMMAND_DELAY);
+        udelay(INTERCOMMAND_DELAY);
 
         rc = snd_korg1212_Send1212Command(korg1212,
                         K1212_DB_ConfigureMiscMemory,
@@ -1029,7 +1071,7 @@
         // --------------------------------------------------------------------------------
         // Initialize the routing and volume tables, then update the card's state.
         // --------------------------------------------------------------------------------
-        TickDelay(INTERCOMMAND_DELAY);
+        udelay(INTERCOMMAND_DELAY);
 
         for (channel = 0; channel < kAudioChannels; channel++) {
                 korg1212->sharedBufferPtr->volumeData[channel] = k1212MaxVolume;
@@ -1039,7 +1081,7 @@
 
         snd_korg1212_WriteADCSensitivity(korg1212);
 
-	TickDelay(INTERCOMMAND_DELAY);
+	udelay(INTERCOMMAND_DELAY);
 	rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SetClockSourceRate,
 					  ClockSourceSelector[korg1212->clkSrcRate],
 					  0, 0, 0);
@@ -1056,7 +1098,6 @@
         wake_up_interruptible(&korg1212->wait);
 }
 
-
 static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
         u32 doorbellValue;
@@ -1092,10 +1133,11 @@
                 // an error occurred - stop the card
                 // ------------------------------------------------------------------------
                 case K1212_ISRCODE_DMAERROR:
-#if K1212_DEBUG_LEVEL > 0
+#if K1212_DEBUG_LEVEL > 1
                         K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DMAE count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
 #endif
                         writel(0, &korg1212->sharedBufferPtr->cardCommand);
+			snd_korg1212_setCardState(korg1212, K1212_STATE_ERRORSTOP);
                         break;
 
                 // ------------------------------------------------------------------------
@@ -1103,14 +1145,14 @@
                 // the semaphore in case someone is waiting for this.
                 // ------------------------------------------------------------------------
                 case K1212_ISRCODE_CARDSTOPPED:
-#if K1212_DEBUG_LEVEL > 0
+#if K1212_DEBUG_LEVEL > 1
                         K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ CSTP count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
 #endif
                         writel(0, &korg1212->sharedBufferPtr->cardCommand);
                         break;
 
                 default:
-#if K1212_DEBUG_LEVEL > 1
+#if K1212_DEBUG_LEVEL > 3
                         K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DFLT count - %ld, %x, cpos=%d [%s].\n", korg1212->irqcount, doorbellValue, 
 				korg1212->currentBuffer, stateName[korg1212->cardState]);
 #endif
@@ -1170,7 +1212,7 @@
 
 static snd_pcm_hardware_t snd_korg1212_playback_info =
 {
-	.info =               (SNDRV_PCM_INFO_MMAP |
+	.info =              (SNDRV_PCM_INFO_MMAP |
                               SNDRV_PCM_INFO_MMAP_VALID |
                               SNDRV_PCM_INFO_INTERLEAVED),
 	.formats =	      SNDRV_PCM_FMTBIT_S16_LE,
@@ -1178,11 +1220,11 @@
                               SNDRV_PCM_RATE_48000),
         .rate_min =           44100,
         .rate_max =           48000,
-        .channels_min =       K1212_CHANNELS,
-        .channels_max =       K1212_CHANNELS,
-        .buffer_bytes_max =   K1212_BUF_SIZE,
-        .period_bytes_min =   K1212_PERIOD_BYTES,
-        .period_bytes_max =   K1212_PERIOD_BYTES,
+        .channels_min =       K1212_MIN_CHANNELS,
+        .channels_max =       K1212_MAX_CHANNELS,
+        .buffer_bytes_max =   K1212_MAX_BUF_SIZE,
+        .period_bytes_min =   K1212_MIN_CHANNELS * 2 * kPlayBufferFrames,
+        .period_bytes_max =   K1212_MAX_CHANNELS * 2 * kPlayBufferFrames,
         .periods_min =        K1212_PERIODS,
         .periods_max =        K1212_PERIODS,
         .fifo_size =          0,
@@ -1190,7 +1232,7 @@
 
 static snd_pcm_hardware_t snd_korg1212_capture_info =
 {
-        .info =               (SNDRV_PCM_INFO_MMAP |
+        .info =              (SNDRV_PCM_INFO_MMAP |
                               SNDRV_PCM_INFO_MMAP_VALID |
                               SNDRV_PCM_INFO_INTERLEAVED),
         .formats =	      SNDRV_PCM_FMTBIT_S16_LE,
@@ -1198,36 +1240,116 @@
                               SNDRV_PCM_RATE_48000),
         .rate_min =           44100,
         .rate_max =           48000,
-        .channels_min =       K1212_CHANNELS,
-        .channels_max =       K1212_CHANNELS,
-        .buffer_bytes_max =   K1212_BUF_SIZE,
-        .period_bytes_min =   K1212_PERIOD_BYTES,
-        .period_bytes_max =   K1212_PERIOD_BYTES,
+        .channels_min =       K1212_MIN_CHANNELS,
+        .channels_max =       K1212_MAX_CHANNELS,
+        .buffer_bytes_max =   K1212_MAX_BUF_SIZE,
+        .period_bytes_min =   K1212_MIN_CHANNELS * 2 * kPlayBufferFrames,
+        .period_bytes_max =   K1212_MAX_CHANNELS * 2 * kPlayBufferFrames,
         .periods_min =        K1212_PERIODS,
         .periods_max =        K1212_PERIODS,
         .fifo_size =          0,
 };
 
-static void snd_korg1212_free_pcm(snd_pcm_t *pcm)
+static int snd_korg1212_silence(korg1212_t *korg1212, int pos, int count, int offset, int size)
 {
-        korg1212_t *korg1212 = (korg1212_t *) pcm->private_data;
+	KorgAudioFrame * dst =  korg1212->playDataBufsPtr[0].bufferData + pos;
+	int i;
+
+#if K1212_DEBUG_LEVEL > 2
+	K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_silence pos=%d offset=%d size=%d count=%d\n", pos, offset, size, count);
+#endif
+	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
 
+	for (i=0; i < count; i++) {
 #if K1212_DEBUG_LEVEL > 0
-		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_free_pcm [%s]\n", stateName[korg1212->cardState]);
+		if ( (void *) dst < (void *) korg1212->playDataBufsPtr ||
+		     (void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) {
+			K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_silence KERNEL EFAULT dst=%p iter=%d\n", dst, i);
+			return -EFAULT;
+		}
+#endif
+		memset((void*) dst + offset, 0, size);
+		dst++;
+	}
+
+	return 0;
+}
+
+static int snd_korg1212_copy_to(korg1212_t *korg1212, void *dst, int pos, int count, int offset, int size)
+{
+	KorgAudioFrame * src =  korg1212->recordDataBufsPtr[0].bufferData + pos;
+	int i, rc;
+
+#if K1212_DEBUG_LEVEL > 2
+	K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_to pos=%d offset=%d size=%d\n", pos, offset, size);
 #endif
+	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
 
-        korg1212->pcm16 = NULL;
+	for (i=0; i < count; i++) {
+#if K1212_DEBUG_LEVEL > 0
+		if ( (void *) src < (void *) korg1212->recordDataBufsPtr ||
+		     (void *) src > (void *) korg1212->recordDataBufsPtr[8].bufferData ) {
+			K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_to KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst, i);
+			return -EFAULT;
+		}
+#endif
+		rc = copy_to_user((void*) dst + offset, src, size);
+		if (rc) {
+#if K1212_DEBUG_LEVEL > 0
+			K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_to USER EFAULT src=%p dst=%p iter=%d\n", src, dst, i);
+#endif
+			return -EFAULT;
+		}
+		src++;
+		dst += size;
+	}
+
+	return 0;
 }
 
-static unsigned int period_bytes[] = { K1212_PERIOD_BYTES };
+static int snd_korg1212_copy_from(korg1212_t *korg1212, void *src, int pos, int count, int offset, int size)
+{
+	KorgAudioFrame * dst =  korg1212->playDataBufsPtr[0].bufferData + pos;
+	int i, rc;
 
-#define PERIOD_BYTES sizeof(period_bytes) / sizeof(period_bytes[0])
+#if K1212_DEBUG_LEVEL > 2
+	K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_from pos=%d offset=%d size=%d count=%d\n", pos, offset, size, count);
+#endif
 
-static snd_pcm_hw_constraint_list_t hw_constraints_period_bytes = {
-        .count = PERIOD_BYTES,
-        .list = period_bytes,
-        .mask = 0
-};
+	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
+
+	for (i=0; i < count; i++) {
+#if K1212_DEBUG_LEVEL > 0
+		if ( (void *) dst < (void *) korg1212->playDataBufsPtr ||
+		     (void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) {
+			K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_from KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst, i);
+			return -EFAULT;
+		}
+#endif
+		rc = copy_from_user((void*) dst + offset, src, size);
+		if (rc) {
+#if K1212_DEBUG_LEVEL > 0
+			K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_from USER EFAULT src=%p dst=%p iter=%d\n", src, dst, i);
+#endif
+			return -EFAULT;
+		}
+		dst++;
+		src += size;
+	}
+
+	return 0;
+}
+
+static void snd_korg1212_free_pcm(snd_pcm_t *pcm)
+{
+        korg1212_t *korg1212 = (korg1212_t *) pcm->private_data;
+
+#if K1212_DEBUG_LEVEL > 0
+		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_free_pcm [%s]\n", stateName[korg1212->cardState]);
+#endif
+
+        korg1212->pcm = NULL;
+}
 
 static int snd_korg1212_playback_open(snd_pcm_substream_t *substream)
 {
@@ -1239,11 +1361,11 @@
 		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_open [%s]\n", stateName[korg1212->cardState]);
 #endif
 
-        spin_lock_irqsave(&korg1212->lock, flags);
+        snd_pcm_set_sync(substream);    // ???
 
-        snd_korg1212_OpenCard(korg1212);
+        spin_lock_irqsave(&korg1212->lock, flags);
 
-        snd_pcm_set_sync(substream);    // ???
+	snd_korg1212_OpenCard(korg1212);
 
         runtime->hw = snd_korg1212_playback_info;
 	runtime->dma_area = (char *) korg1212->playDataBufsPtr;
@@ -1251,14 +1373,15 @@
 
         korg1212->playback_substream = substream;
         korg1212->periodsize = K1212_PERIODS;
+	korg1212->channels = K1212_CHANNELS;
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
 
-        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, K1212_BUF_SIZE, K1212_BUF_SIZE);
-        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames, kPlayBufferFrames);
         return 0;
 }
 
+
 static int snd_korg1212_capture_open(snd_pcm_substream_t *substream)
 {
         unsigned long flags;
@@ -1269,11 +1392,11 @@
 		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_open [%s]\n", stateName[korg1212->cardState]);
 #endif
 
-        spin_lock_irqsave(&korg1212->lock, flags);
+        snd_pcm_set_sync(substream);    // ???
 
-        snd_korg1212_OpenCard(korg1212);
+        spin_lock_irqsave(&korg1212->lock, flags);
 
-        snd_pcm_set_sync(substream);    // ???
+	snd_korg1212_OpenCard(korg1212);
 
         runtime->hw = snd_korg1212_capture_info;
 	runtime->dma_area = (char *) korg1212->recordDataBufsPtr;
@@ -1281,11 +1404,11 @@
 
         korg1212->capture_substream = substream;
         korg1212->periodsize = K1212_PERIODS;
+	korg1212->channels = K1212_CHANNELS;
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
 
-        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, K1212_BUF_SIZE, K1212_BUF_SIZE);
-        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames, kPlayBufferFrames);
         return 0;
 }
 
@@ -1298,12 +1421,14 @@
 		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_close [%s]\n", stateName[korg1212->cardState]);
 #endif
 
+	snd_korg1212_silence(korg1212, 0, K1212_MAX_SAMPLES, 0, korg1212->channels * 2);
+
         spin_lock_irqsave(&korg1212->lock, flags);
 
         korg1212->playback_substream = NULL;
         korg1212->periodsize = 0;
 
-        snd_korg1212_CloseCard(korg1212);
+	snd_korg1212_CloseCard(korg1212);
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
         return 0;
@@ -1323,43 +1448,28 @@
         korg1212->capture_substream = NULL;
         korg1212->periodsize = 0;
 
-        snd_korg1212_CloseCard(korg1212);
+	snd_korg1212_CloseCard(korg1212);
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
         return 0;
 }
 
-static int snd_korg1212_channel_info(snd_pcm_substream_t *substream,
-				    snd_pcm_channel_info_t *info)
-{
-	int chn = info->channel;
-
-	// snd_assert(info->channel < kAudioChannels + 1, return -EINVAL);
-
-        info->offset = 0;
-        // if (chn < k16BitChannels) {
-                info->first = chn * 16;
-        // } else {
-        //         info->first = k16BitChannels * 16 + (chn - k16BitChannels - 1) * 32;
-        // }
-        info->step = sizeof(KorgAudioFrame) * 8;
-
-#if K1212_DEBUG_LEVEL > 0
-		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_channel_info %d:, offset=%ld, first=%d, step=%d\n", chn, info->offset, info->first, info->step);
-#endif
-
-	return 0;
-}
-
 static int snd_korg1212_ioctl(snd_pcm_substream_t *substream,
 			     unsigned int cmd, void *arg)
 {
 #if K1212_DEBUG_LEVEL > 0
 		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_ioctl: cmd=%d\n", cmd);
 #endif
+
 	if (cmd == SNDRV_PCM_IOCTL1_CHANNEL_INFO ) {
 		snd_pcm_channel_info_t *info = arg;
-		return snd_korg1212_channel_info(substream, info);
+        	info->offset = 0;
+        	info->first = info->channel * 16;
+        	info->step = 256;
+#if K1212_DEBUG_LEVEL > 0
+		K1212_DEBUG_PRINTK("K1212_DEBUG: channel_info %d:, offset=%ld, first=%d, step=%d\n", info->channel, info->offset, info->first, info->step);
+#endif
+		return 0;
 	}
 
         return snd_pcm_lib_ioctl(substream, cmd, arg);
@@ -1381,13 +1491,14 @@
                 spin_unlock_irqrestore(&korg1212->lock, flags);
                 return err;
         }
-
+/*
         if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
                 spin_unlock_irqrestore(&korg1212->lock, flags);
                 return -EINVAL;
         }
-
-        korg1212->periodsize = K1212_BLOCK_SIZE;
+*/
+	korg1212->channels = params_channels(params);
+        korg1212->periodsize = K1212_PERIOD_BYTES;
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
 
@@ -1398,6 +1509,7 @@
 {
         korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
         unsigned long flags;
+	int rc;
 
 #if K1212_DEBUG_LEVEL > 0
 		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_prepare [%s]\n", stateName[korg1212->cardState]);
@@ -1405,18 +1517,19 @@
 
         spin_lock_irqsave(&korg1212->lock, flags);
 
-        snd_korg1212_SetupForPlay(korg1212);
-
-        korg1212->currentBuffer = -1;
+        rc = snd_korg1212_SetupForPlay(korg1212);
+        korg1212->currentBuffer = 0;
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
-        return 0;
+
+	return rc ? -EINVAL : 0;
 }
 
 static int snd_korg1212_trigger(snd_pcm_substream_t *substream,
                            int cmd)
 {
         korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
+	int rc;
 
 #if K1212_DEBUG_LEVEL > 0
 		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger [%s] cmd=%d\n", stateName[korg1212->cardState], cmd);
@@ -1424,72 +1537,82 @@
 
         switch (cmd) {
                 case SNDRV_PCM_TRIGGER_START:
-                        korg1212->running = 1;
-                        snd_korg1212_TriggerPlay(korg1212);
+/*
+			if (korg1212->running) {
+#if K1212_DEBUG_LEVEL > 1
+				K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger: Already running?\n");
+#endif
+				break;
+			}
+*/
+                        korg1212->running++;
+                        rc = snd_korg1212_TriggerPlay(korg1212);
                         break;
 
                 case SNDRV_PCM_TRIGGER_STOP:
-                        korg1212->running = 0;
-                        snd_korg1212_StopPlay(korg1212);
+/*
+			if (!korg1212->running) {
+#if K1212_DEBUG_LEVEL > 1
+				K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger: Already stopped?\n");
+#endif
+				break;
+			}
+*/
+                        korg1212->running--;
+                        rc = snd_korg1212_StopPlay(korg1212);
                         break;
 
                 default:
-                        return -EINVAL;
+			rc = 1;
+			break;
         }
-        return 0;
+        return rc ? -EINVAL : 0;
 }
 
-static snd_pcm_uframes_t snd_korg1212_pointer(snd_pcm_substream_t *substream)
+static snd_pcm_uframes_t snd_korg1212_playback_pointer(snd_pcm_substream_t *substream)
 {
         korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
         snd_pcm_uframes_t pos;
 
-	if (korg1212->currentBuffer < 0)
-		return 0;
-
 	pos = korg1212->currentBuffer * kPlayBufferFrames;
 
-#if K1212_DEBUG_LEVEL > 1
-		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_pointer [%s] %ld\n", stateName[korg1212->cardState], pos);
+#if K1212_DEBUG_LEVEL > 2
+	K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_pointer [%s] %ld\n", 
+			stateName[korg1212->cardState], pos);
 #endif
 
         return pos;
 }
 
-static int snd_korg1212_playback_copy(snd_pcm_substream_t *substream,
-                        int channel, /* not used (interleaved data) */
-                        snd_pcm_uframes_t pos,
-                        void *src,
-                        snd_pcm_uframes_t count)
+static snd_pcm_uframes_t snd_korg1212_capture_pointer(snd_pcm_substream_t *substream)
 {
         korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
-	KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos;
+        snd_pcm_uframes_t pos;
 
-#if K1212_DEBUG_LEVEL > 0
-		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
+	pos = korg1212->currentBuffer * kPlayBufferFrames;
+
+#if K1212_DEBUG_LEVEL > 2
+	K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_pointer [%s] %ld\n",
+			stateName[korg1212->cardState], pos);
 #endif
- 
-	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
 
-        return copy_from_user(dst, src, count * K1212_FRAME_SIZE) ? -EFAULT : 0;
+        return pos;
 }
 
-static int snd_korg1212_capture_copy(snd_pcm_substream_t *substream,
+static int snd_korg1212_playback_copy(snd_pcm_substream_t *substream,
                         int channel, /* not used (interleaved data) */
                         snd_pcm_uframes_t pos,
-                        void *dst,
+                        void *src,
                         snd_pcm_uframes_t count)
 {
         korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
-	KorgAudioFrame * src = korg1212->recordDataBufsPtr[0].bufferData + pos;
 
-#if K1212_DEBUG_LEVEL > 0
-		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
+#if K1212_DEBUG_LEVEL > 2
+		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
 #endif
+ 
+	return snd_korg1212_copy_from(korg1212, src, pos, count, 0, korg1212->channels * 2);
 
-	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
-
-        return copy_to_user(dst, src, count * K1212_FRAME_SIZE) ? -EFAULT : 0;
 }
 
 static int snd_korg1212_playback_silence(snd_pcm_substream_t *substream,
@@ -1498,17 +1621,27 @@
                            snd_pcm_uframes_t count)
 {
         korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
-	KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos;
 
 #if K1212_DEBUG_LEVEL > 0
 		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_silence [%s]\n", stateName[korg1212->cardState]);
 #endif
 
-	snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
+	return snd_korg1212_silence(korg1212, pos, count, 0, korg1212->channels * 2);
+}
 
-        memset(dst, 0, count * K1212_FRAME_SIZE);
+static int snd_korg1212_capture_copy(snd_pcm_substream_t *substream,
+                        int channel, /* not used (interleaved data) */
+                        snd_pcm_uframes_t pos,
+                        void *dst,
+                        snd_pcm_uframes_t count)
+{
+        korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
 
-        return 0;
+#if K1212_DEBUG_LEVEL > 2
+		K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
+#endif
+
+	return snd_korg1212_copy_to(korg1212, dst, pos, count, 0, korg1212->channels * 2);
 }
 
 static snd_pcm_ops_t snd_korg1212_playback_ops = {
@@ -1518,7 +1651,7 @@
         .hw_params =	snd_korg1212_hw_params,
         .prepare =	snd_korg1212_prepare,
         .trigger =	snd_korg1212_trigger,
-        .pointer =	snd_korg1212_pointer,
+        .pointer =	snd_korg1212_playback_pointer,
         .copy =		snd_korg1212_playback_copy,
         .silence =	snd_korg1212_playback_silence,
 };
@@ -1530,7 +1663,7 @@
 	.hw_params =	snd_korg1212_hw_params,
 	.prepare =	snd_korg1212_prepare,
 	.trigger =	snd_korg1212_trigger,
-	.pointer =	snd_korg1212_pointer,
+	.pointer =	snd_korg1212_capture_pointer,
 	.copy =		snd_korg1212_capture_copy,
 };
 
@@ -1555,7 +1688,7 @@
 
         u->value.integer.value[0] = korg1212->volumePhase[i];
 
-	if (i >= 8) 
+	if (i >= 8)
         	u->value.integer.value[1] = korg1212->volumePhase[i+1];
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
@@ -1703,13 +1836,13 @@
 
 	i = kcontrol->private_value;
 
-	if (u->value.enumerated.item[0] != (unsigned int)korg1212->sharedBufferPtr->volumeData[i]) {
+	if (u->value.enumerated.item[0] != (unsigned) korg1212->sharedBufferPtr->volumeData[i]) {
 		korg1212->sharedBufferPtr->routeData[i] = u->value.enumerated.item[0];
 		change = 1;
 	}
 
 	if (i >= 8) {
-		if (u->value.enumerated.item[1] != (unsigned int)korg1212->sharedBufferPtr->volumeData[i+1]) {
+		if (u->value.enumerated.item[1] != (unsigned) korg1212->sharedBufferPtr->volumeData[i+1]) {
 			korg1212->sharedBufferPtr->routeData[i+1] = u->value.enumerated.item[1];
 			change = 1;
 		}
@@ -1720,7 +1853,7 @@
         return change;
 }
 
-static int snd_korg1212_control_analog_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_korg1212_control_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
         uinfo->count = 2;
@@ -1729,7 +1862,7 @@
         return 0;
 }
 
-static int snd_korg1212_control_analog_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u)
+static int snd_korg1212_control_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u)
 {
 	korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
@@ -1744,7 +1877,7 @@
         return 0;
 }
 
-static int snd_korg1212_control_analog_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u)
+static int snd_korg1212_control_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u)
 {
 	korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol);
 	unsigned long flags;
@@ -1855,9 +1988,9 @@
                 .access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
                 .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
                 .name =		"ADC Attenuation",
-                .info =		snd_korg1212_control_analog_info,
-                .get =		snd_korg1212_control_analog_get,
-                .put =		snd_korg1212_control_analog_put,
+                .info =		snd_korg1212_control_info,
+                .get =		snd_korg1212_control_get,
+                .put =		snd_korg1212_control_put,
         }
 };
 
@@ -1875,7 +2008,7 @@
 	snd_iprintf(buffer, korg1212->card->longname);
 	snd_iprintf(buffer, " (index #%d)\n", korg1212->card->number + 1);
 	snd_iprintf(buffer, "\nGeneral settings\n");
-	snd_iprintf(buffer, "    period size: %d bytes\n", K1212_BLOCK_SIZE);
+	snd_iprintf(buffer, "    period size: %d bytes\n", K1212_PERIOD_BYTES);
 	snd_iprintf(buffer, "     clock mode: %s\n", clockSourceName[korg1212->clkSrcRate] );
 	snd_iprintf(buffer, "  left ADC Sens: %d\n", korg1212->leftADCInSens );
 	snd_iprintf(buffer, " right ADC Sens: %d\n", korg1212->rightADCInSens );
@@ -1901,19 +2034,132 @@
 		snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read);
 }
 
-static int __devinit snd_korg1212_create(korg1212_t *korg1212)
+static int
+snd_korg1212_free(korg1212_t *korg1212)
+{
+        snd_korg1212_TurnOffIdleMonitor(korg1212);
+
+        if (korg1212->irq >= 0) {
+                synchronize_irq(korg1212->irq);                
+                snd_korg1212_DisableCardInterrupts(korg1212);
+                free_irq(korg1212->irq, (void *)korg1212);
+                korg1212->irq = -1;
+        }
+        
+        if (korg1212->iobase != 0) {
+                iounmap((void *)korg1212->iobase);
+                korg1212->iobase = 0;
+        }
+        
+        if (korg1212->res_iomem != NULL) {
+                release_resource(korg1212->res_iomem);
+                kfree_nocheck(korg1212->res_iomem);
+                korg1212->res_iomem = NULL;
+        }
+        
+        if (korg1212->res_ioport != NULL) {
+                release_resource(korg1212->res_ioport);
+                kfree_nocheck(korg1212->res_ioport);
+                korg1212->res_ioport = NULL;
+        }
+        
+        if (korg1212->res_iomem2 != NULL) {
+                release_resource(korg1212->res_iomem2);
+                kfree_nocheck(korg1212->res_iomem2);
+                korg1212->res_iomem2 = NULL;
+        }
+
+        // ----------------------------------------------------
+        // free up memory resources used for the DSP download.
+        // ----------------------------------------------------
+        if (korg1212->dspMemPtr) {
+                snd_free_pci_pages(korg1212->pci, korg1212->dspCodeSize,
+                                   korg1212->dspMemPtr, (dma_addr_t)korg1212->dspMemPhy);
+                korg1212->dspMemPhy = 0;
+                korg1212->dspMemPtr = 0;
+                korg1212->dspCodeSize = 0;
+        }
+
+#ifndef K1212_LARGEALLOC
+
+        // ------------------------------------------------------
+        // free up memory resources used for the Play/Rec Buffers
+        // ------------------------------------------------------
+	if (korg1212->playDataBufsPtr) {
+                snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
+                                   korg1212->playDataBufsPtr, (dma_addr_t)korg1212->PlayDataPhy);
+		korg1212->PlayDataPhy = 0;
+		korg1212->playDataBufsPtr = NULL;
+        }
+
+	if (korg1212->recordDataBufsPtr) {
+                snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
+                                   korg1212->recordDataBufsPtr, (dma_addr_t)korg1212->RecDataPhy);
+		korg1212->RecDataPhy = 0;
+		korg1212->recordDataBufsPtr = NULL;
+        }
+
+#endif
+
+        // ----------------------------------------------------
+        // free up memory resources used for the Shared Buffers
+        // ----------------------------------------------------
+	if (korg1212->sharedBufferPtr) {
+                snd_free_pci_pages(korg1212->pci, (u32) sizeof(KorgSharedBuffer),
+                                   korg1212->sharedBufferPtr, (dma_addr_t)korg1212->sharedBufferPhy);
+		korg1212->sharedBufferPhy = 0;
+		korg1212->sharedBufferPtr = NULL;
+        }
+        
+        snd_magic_kfree(korg1212);
+        return 0;
+}
+
+static int snd_korg1212_dev_free(snd_device_t *device)
+{
+        korg1212_t *korg1212 = snd_magic_cast(korg1212_t, device->device_data, return -ENXIO);
+#if K1212_DEBUG_LEVEL > 0
+        K1212_DEBUG_PRINTK("K1212_DEBUG: Freeing device\n");
+#endif
+	return snd_korg1212_free(korg1212);
+}
+
+static int __devinit snd_korg1212_create(snd_card_t * card, struct pci_dev *pci,
+                                         korg1212_t ** rchip)
+
 {
-        struct pci_dev *pci = korg1212->pci;
         int err;
         unsigned int i;
 	unsigned ioport_size, iomem_size, iomem2_size;
 	dma_addr_t phys_addr;
+        korg1212_t * korg1212;
+
+        static snd_device_ops_t ops = {
+                .dev_free = snd_korg1212_dev_free,
+        };
+
+        * rchip = NULL;
+        if ((err = pci_enable_device(pci)) < 0)
+                return err;
+
+        korg1212 = snd_magic_kcalloc(korg1212_t, 0, GFP_KERNEL);
+        if (korg1212 == NULL)
+                return -ENOMEM;
+
+	korg1212->card = card;
+	korg1212->pci = pci;
+
+        init_waitqueue_head(&korg1212->wait);
+        spin_lock_init(&korg1212->lock);
 
         korg1212->irq = -1;
         korg1212->clkSource = K1212_CLKIDX_Local;
         korg1212->clkRate = 44100;
         korg1212->inIRQ = 0;
         korg1212->running = 0;
+	korg1212->opencnt = 0;
+	korg1212->playcnt = 0;
+	korg1212->setcnt = 0;
         snd_korg1212_setCardState(korg1212, K1212_STATE_UNINITIALIZED);
         korg1212->idleMonitorOn = 0;
         korg1212->clkSrcRate = K1212_CLKIDX_LocalAt44_1K;
@@ -1923,9 +2169,6 @@
         for (i=0; i<kAudioChannels; i++)
                 korg1212->volumePhase[i] = 0;
 
-        if ((err = pci_enable_device(pci)) < 0)
-                return err;
-
         korg1212->iomem = pci_resource_start(korg1212->pci, 0);
         korg1212->ioport = pci_resource_start(korg1212->pci, 1);
         korg1212->iomem2 = pci_resource_start(korg1212->pci, 2);
@@ -1948,27 +2191,27 @@
 
         korg1212->res_iomem = request_mem_region(korg1212->iomem, iomem_size, "korg1212");
         if (korg1212->res_iomem == NULL) {
-		snd_printk("unable to grab region 0x%lx-0x%lx\n",
+		snd_printk(KERN_ERR "unable to grab region 0x%lx-0x%lx\n",
                            korg1212->iomem, korg1212->iomem + iomem_size - 1);
                 return -EBUSY;
         }
 
         korg1212->res_ioport = request_region(korg1212->ioport, ioport_size, "korg1212");
         if (korg1212->res_ioport == NULL) {
-		snd_printk("unable to grab region 0x%lx-0x%lx\n",
+		snd_printk(KERN_ERR "unable to grab region 0x%lx-0x%lx\n",
                            korg1212->ioport, korg1212->ioport + ioport_size - 1);
                 return -EBUSY;
         }
 
         korg1212->res_iomem2 = request_mem_region(korg1212->iomem2, iomem2_size, "korg1212");
         if (korg1212->res_iomem2 == NULL) {
-		snd_printk("unable to grab region 0x%lx-0x%lx\n",
+		snd_printk(KERN_ERR "unable to grab region 0x%lx-0x%lx\n",
                            korg1212->iomem2, korg1212->iomem2 + iomem2_size - 1);
                 return -EBUSY;
         }
 
         if ((korg1212->iobase = (unsigned long) ioremap(korg1212->iomem, iomem_size)) == 0) {
-		snd_printk("unable to remap memory region 0x%lx-0x%lx\n", korg1212->iobase,
+		snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", korg1212->iobase,
                            korg1212->iobase + iomem_size - 1);
                 return -EBUSY;
         }
@@ -1978,14 +2221,12 @@
                           "korg1212", (void *) korg1212);
 
         if (err) {
-		snd_printk("unable to grab IRQ %d\n", pci->irq);
+		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                 return -EBUSY;
         }
 
         korg1212->irq = pci->irq;
 
-        init_waitqueue_head(&korg1212->wait);
-        spin_lock_init(&korg1212->lock);
 	pci_set_master(korg1212->pci);
 
         korg1212->statusRegPtr = (u32 *) (korg1212->iobase + STATUS_REG_OFFSET);
@@ -2029,7 +2270,7 @@
 	korg1212->sharedBufferPhy = (unsigned long)phys_addr;
 
         if (korg1212->sharedBufferPtr == NULL) {
-		snd_printk("can not allocate shared buffer memory (%d bytes)\n", sizeof(KorgSharedBuffer));
+		snd_printk(KERN_ERR "can not allocate shared buffer memory (%d bytes)\n", sizeof(KorgSharedBuffer));
                 return -ENOMEM;
         }
 
@@ -2045,7 +2286,7 @@
 	korg1212->PlayDataPhy = (u32)phys_addr;
 
         if (korg1212->playDataBufsPtr == NULL) {
-		snd_printk("can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
+		snd_printk(KERN_ERR "can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
                 return -ENOMEM;
         }
 
@@ -2058,7 +2299,7 @@
 	korg1212->RecDataPhy = (u32)phys_addr;
 
         if (korg1212->recordDataBufsPtr == NULL) {
-		snd_printk("can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
+		snd_printk(KERN_ERR "can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
                 return -ENOMEM;
         }
 
@@ -2086,7 +2327,7 @@
 	korg1212->dspMemPhy = (u32)phys_addr;
 
         if (korg1212->dspMemPtr == NULL) {
-		snd_printk("can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
+		snd_printk(KERN_ERR "can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
                 return -ENOMEM;
         }
 
@@ -2106,7 +2347,7 @@
 
 	mdelay(CARD_BOOT_DELAY_IN_MS);
 
-        if (snd_korg1212_downloadDSPCode(korg1212))
+        if (snd_korg1212_downloadDSPCode(korg1212)) 
         	return -EBUSY;
 
 	printk(KERN_INFO "dspMemPhy       = %08x U[%08x]\n"
@@ -2122,17 +2363,21 @@
                korg1212->RoutingTablePhy, LowerWordSwap(korg1212->RoutingTablePhy),
                korg1212->AdatTimeCodePhy, LowerWordSwap(korg1212->AdatTimeCodePhy));
 
-        if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm16)) < 0)
+        if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm)) < 0)
                 return err;
 
-        korg1212->pcm16->private_data = korg1212;
-        korg1212->pcm16->private_free = snd_korg1212_free_pcm;
-        strcpy(korg1212->pcm16->name, "korg1212");
+	korg1212->pcm->private_data = korg1212;
+        korg1212->pcm->private_free = snd_korg1212_free_pcm;
+        strcpy(korg1212->pcm->name, "korg1212");
+
+        snd_pcm_set_ops(korg1212->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_korg1212_playback_ops);
+        
+	snd_pcm_set_ops(korg1212->pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_korg1212_capture_ops);
 
-        snd_pcm_set_ops(korg1212->pcm16, SNDRV_PCM_STREAM_PLAYBACK, &snd_korg1212_playback_ops);
-        snd_pcm_set_ops(korg1212->pcm16, SNDRV_PCM_STREAM_CAPTURE, &snd_korg1212_capture_ops);
+	korg1212->pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
 
-	korg1212->pcm16->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
+	//snd_pcm_lib_preallocate_pages_for_all(korg1212->pcm,
+	//			K1212_MAX_BUF_SIZE, K1212_MAX_BUF_SIZE, GFP_KERNEL);
 
         for (i = 0; i < K1212_CONTROL_ELEMENTS; i++) {
                 err = snd_ctl_add(korg1212->card, snd_ctl_new1(&snd_korg1212_controls[i], korg1212));
@@ -2141,103 +2386,21 @@
         }
 
         snd_korg1212_proc_init(korg1212);
-
-	return 0;
-
-}
-
-static void
-snd_korg1212_free(void *private_data)
-{
-        korg1212_t *korg1212 = (korg1212_t *)private_data;
-
-        if (korg1212 == NULL) {
-                return;
-        }
-
-        snd_korg1212_TurnOffIdleMonitor(korg1212);
-
-        snd_korg1212_DisableCardInterrupts(korg1212);
-
-        if (korg1212->irq >= 0) {
-                free_irq(korg1212->irq, (void *)korg1212);
-                korg1212->irq = -1;
-        }
-        if (korg1212->iobase != 0) {
-                iounmap((void *)korg1212->iobase);
-                korg1212->iobase = 0;
-        }
-        if (korg1212->res_iomem != NULL) {
-                release_resource(korg1212->res_iomem);
-                kfree_nocheck(korg1212->res_iomem);
-                korg1212->res_iomem = NULL;
-        }
-        if (korg1212->res_ioport != NULL) {
-                release_resource(korg1212->res_ioport);
-                kfree_nocheck(korg1212->res_ioport);
-                korg1212->res_ioport = NULL;
-        }
-        if (korg1212->res_iomem2 != NULL) {
-                release_resource(korg1212->res_iomem2);
-                kfree_nocheck(korg1212->res_iomem2);
-                korg1212->res_iomem2 = NULL;
-        }
-
-        // ----------------------------------------------------
-        // free up memory resources used for the DSP download.
-        // ----------------------------------------------------
-        if (korg1212->dspMemPtr) {
-                snd_free_pci_pages(korg1212->pci, korg1212->dspCodeSize,
-                                   korg1212->dspMemPtr, (dma_addr_t)korg1212->dspMemPhy);
-                korg1212->dspMemPhy = 0;
-                korg1212->dspMemPtr = 0;
-                korg1212->dspCodeSize = 0;
-        }
-
-#ifndef K1212_LARGEALLOC
-
-        // ------------------------------------------------------
-        // free up memory resources used for the Play/Rec Buffers
-        // ------------------------------------------------------
-	if (korg1212->playDataBufsPtr) {
-                snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
-                                   korg1212->playDataBufsPtr, (dma_addr_t)korg1212->PlayDataPhy);
-		korg1212->PlayDataPhy = 0;
-		korg1212->playDataBufsPtr = NULL;
-        }
-
-	if (korg1212->recordDataBufsPtr) {
-                snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
-                                   korg1212->recordDataBufsPtr, (dma_addr_t)korg1212->RecDataPhy);
-		korg1212->RecDataPhy = 0;
-		korg1212->recordDataBufsPtr = NULL;
+        
+        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, korg1212, &ops)) < 0) {
+                snd_korg1212_free(korg1212);
+                return err;
         }
+        
+        * rchip = korg1212;
+	return 0;
 
-#endif
-
-        // ----------------------------------------------------
-        // free up memory resources used for the Shared Buffers
-        // ----------------------------------------------------
-	if (korg1212->sharedBufferPtr) {
-                snd_free_pci_pages(korg1212->pci, (u32) sizeof(KorgSharedBuffer),
-                                   korg1212->sharedBufferPtr, (dma_addr_t)korg1212->sharedBufferPhy);
-		korg1212->sharedBufferPhy = 0;
-		korg1212->sharedBufferPtr = NULL;
-        }
 }
 
 /*
  * Card initialisation
  */
 
-static void snd_korg1212_card_free(snd_card_t *card)
-{
-#if K1212_DEBUG_LEVEL > 0
-        K1212_DEBUG_PRINTK("K1212_DEBUG: Freeing card\n");
-#endif
-	snd_korg1212_free(card->private_data);
-}
-
 static int __devinit
 snd_korg1212_probe(struct pci_dev *pci,
 		const struct pci_device_id *pci_id)
@@ -2254,16 +2417,11 @@
 		dev++;
 		return -ENOENT;
 	}
-	if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-				 sizeof(korg1212_t))) == NULL)
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+        if (card == NULL)
 		return -ENOMEM;
 
-	card->private_free = snd_korg1212_card_free;
-	korg1212 = (korg1212_t *)card->private_data;
-	korg1212->card = card;
-	korg1212->pci = pci;
-
-	if ((err = snd_korg1212_create(korg1212)) < 0) {
+        if ((err = snd_korg1212_create(card, pci, &korg1212)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
@@ -2281,22 +2439,23 @@
 		snd_card_free(card);
 		return err;
 	}
-	pci_set_drvdata(pci, card);
+	pci_set_drvdata(pci, korg1212);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_korg1212_remove(struct pci_dev *pci)
 {
-	snd_card_free(pci_get_drvdata(pci));
+	korg1212_t *korg1212 = pci_get_drvdata(pci);
+	snd_card_free(korg1212->card);
 	pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver driver = {
-	.name	  = "korg1212",
+	.name = "korg1212",
 	.id_table = snd_korg1212_ids,
-	.probe	  = snd_korg1212_probe,
-	.remove	  = __devexit_p(snd_korg1212_remove),
+	.probe = snd_korg1212_probe,
+	.remove = __devexit_p(snd_korg1212_remove),
 };
 
 static int __init alsa_card_korg1212_init(void)
diff -urN linux-2.5.65-bk1/sound/pci/maestro3.c linux-2.5.65-bk2/sound/pci/maestro3.c
--- linux-2.5.65-bk1/sound/pci/maestro3.c	Mon Mar 17 13:44:09 2003
+++ linux-2.5.65-bk2/sound/pci/maestro3.c	Mon Mar 31 12:39:51 2003
@@ -941,13 +941,14 @@
 	},
 	/* Dell Inspiron 8000 */
 	{
-		.name = "Dell Insprion 8000",
+		.name = "Dell Inspiron 8000",
 		.vendor = 0x1028,
 		.device = 0x00a4,
 		.amp_gpio = -1,
 		.irda_workaround = 1,
 	},
-	/* FIXME: Inspiron 8100 and 8200 ids should be here, too */
+	/* FIXME: Inspiron 8100 id should probably be here, too
+	 * (8200 irrelevant: has intel8x0 with CS4205) */
 	/* END */
 	{ 0 }
 };
diff -urN linux-2.5.65-bk1/sound/pci/rme9652/hammerfall_mem.c linux-2.5.65-bk2/sound/pci/rme9652/hammerfall_mem.c
--- linux-2.5.65-bk1/sound/pci/rme9652/hammerfall_mem.c	Mon Mar 17 13:43:42 2003
+++ linux-2.5.65-bk2/sound/pci/rme9652/hammerfall_mem.c	Mon Mar 31 12:39:51 2003
@@ -25,7 +25,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
-    $Id: hammerfall_mem.c,v 1.7 2003/01/06 14:21:28 perex Exp $
+    $Id: hammerfall_mem.c,v 1.8 2003/02/25 13:35:44 perex Exp $
 
 
     Tue Oct 17 2000  Jaroslav Kysela <perex@suse.cz>
diff -urN linux-2.5.65-bk1/sound/pci/rme9652/hdsp.c linux-2.5.65-bk2/sound/pci/rme9652/hdsp.c
--- linux-2.5.65-bk1/sound/pci/rme9652/hdsp.c	Mon Mar 17 13:44:02 2003
+++ linux-2.5.65-bk2/sound/pci/rme9652/hdsp.c	Mon Mar 31 12:39:51 2003
@@ -72,7 +72,7 @@
 MODULE_DESCRIPTION("RME Hammerfall DSP");
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{RME,Hammerfall-DSP},");
+MODULE_DEVICES("{{RME,Hammerfall-DSP}}");
 
 typedef enum {
 	Digiface,
@@ -2310,7 +2310,8 @@
 
 	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
 	snd_assert(channel_buf != NULL, return -EIO);
-	copy_from_user(channel_buf + pos * 4, src, count * 4);
+	if (copy_from_user(channel_buf + pos * 4, src, count * 4))
+		return -EFAULT;
 	return count;
 }
 
@@ -2324,7 +2325,8 @@
 
 	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
 	snd_assert(channel_buf != NULL, return -EIO);
-	copy_to_user(dst, channel_buf + pos * 4, count * 4);
+	if (copy_to_user(dst, channel_buf + pos * 4, count * 4))
+		return -EFAULT;
 	return count;
 }
 
@@ -2634,16 +2636,16 @@
 	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 	if (r->min > 48000) {
 		snd_interval_t t = {
-			min: hdsp->ds_channels,
-			max: hdsp->ds_channels,
-			integer: 1,
+			.min = hdsp->ds_channels,
+			.max = hdsp->ds_channels,
+			.integer = 1,
 		};
 		return snd_interval_refine(c, &t);
 	} else if (r->max < 64000) {
 		snd_interval_t t = {
-			min: hdsp->ss_channels,
-			max: hdsp->ss_channels,
-			integer: 1,
+			.min = hdsp->ss_channels,
+			.max = hdsp->ss_channels,
+			.integer = 1,
 		};
 		return snd_interval_refine(c, &t);
 	}
@@ -2658,16 +2660,16 @@
 	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 	if (c->min >= hdsp->ss_channels) {
 		snd_interval_t t = {
-			min: 32000,
-			max: 48000,
-			integer: 1,
+			.min = 32000,
+			.max = 48000,
+			.integer = 1,
 		};
 		return snd_interval_refine(r, &t);
 	} else if (c->max <= hdsp->ds_channels) {
 		snd_interval_t t = {
-			min: 64000,
-			max: 96000,
-			integer: 1,
+			.min = 64000,
+			.max = 96000,
+			.integer = 1,
 		};
 		return snd_interval_refine(r, &t);
 	}
diff -urN linux-2.5.65-bk1/sound/pci/rme9652/rme9652.c linux-2.5.65-bk2/sound/pci/rme9652/rme9652.c
--- linux-2.5.65-bk1/sound/pci/rme9652/rme9652.c	Mon Mar 17 13:44:05 2003
+++ linux-2.5.65-bk2/sound/pci/rme9652/rme9652.c	Mon Mar 31 12:39:51 2003
@@ -2326,16 +2326,16 @@
 	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 	if (r->min > 48000) {
 		snd_interval_t t = {
-			min: rme9652->ds_channels,
-			max: rme9652->ds_channels,
-			integer: 1,
+			.min = rme9652->ds_channels,
+			.max = rme9652->ds_channels,
+			.integer = 1,
 		};
 		return snd_interval_refine(c, &t);
 	} else if (r->max < 88200) {
 		snd_interval_t t = {
-			min: rme9652->ss_channels,
-			max: rme9652->ss_channels,
-			integer: 1,
+			.min = rme9652->ss_channels,
+			.max = rme9652->ss_channels,
+			.integer = 1,
 		};
 		return snd_interval_refine(c, &t);
 	}
@@ -2350,16 +2350,16 @@
 	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 	if (c->min >= rme9652->ss_channels) {
 		snd_interval_t t = {
-			min: 44100,
-			max: 48000,
-			integer: 1,
+			.min = 44100,
+			.max = 48000,
+			.integer = 1,
 		};
 		return snd_interval_refine(r, &t);
 	} else if (c->max <= rme9652->ds_channels) {
 		snd_interval_t t = {
-			min: 88200,
-			max: 96000,
-			integer: 1,
+			.min = 88200,
+			.max = 96000,
+			.integer = 1,
 		};
 		return snd_interval_refine(r, &t);
 	}
diff -urN linux-2.5.65-bk1/sound/pci/sonicvibes.c linux-2.5.65-bk2/sound/pci/sonicvibes.c
--- linux-2.5.65-bk1/sound/pci/sonicvibes.c	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/sound/pci/sonicvibes.c	Mon Mar 31 12:39:51 2003
@@ -267,14 +267,14 @@
 MODULE_DEVICE_TABLE(pci, snd_sonic_ids);
 
 static ratden_t sonicvibes_adc_clock = {
-	num_min: 4000 * 65536,
-	num_max: 48000UL * 65536,
-	num_step: 1,
-	den: 65536,
+	.num_min = 4000 * 65536,
+	.num_max = 48000UL * 65536,
+	.num_step = 1,
+	.den = 65536,
 };
 static snd_pcm_hw_constraint_ratdens_t snd_sonicvibes_hw_constraints_adc_clock = {
-	nrats: 1,
-	rats: &sonicvibes_adc_clock,
+	.nrats = 1,
+	.rats = &sonicvibes_adc_clock,
 };
 
 /*
diff -urN linux-2.5.65-bk1/sound/pci/trident/trident.c linux-2.5.65-bk2/sound/pci/trident/trident.c
--- linux-2.5.65-bk1/sound/pci/trident/trident.c	Mon Mar 17 13:43:37 2003
+++ linux-2.5.65-bk2/sound/pci/trident/trident.c	Mon Mar 31 12:39:51 2003
@@ -100,7 +100,7 @@
 
 	if ((err = snd_trident_create(card, pci,
 				      pcm_channels[dev],
-				      2,
+				      ((pci->vendor << 16) | pci->device) == TRIDENT_DEVICE_ID_SI7018 ? 1 : 2,
 				      wavetable_size[dev],
 				      &trident)) < 0) {
 		snd_card_free(card);
diff -urN linux-2.5.65-bk1/sound/pci/trident/trident_main.c linux-2.5.65-bk2/sound/pci/trident/trident_main.c
--- linux-2.5.65-bk1/sound/pci/trident/trident_main.c	Mon Mar 17 13:44:16 2003
+++ linux-2.5.65-bk2/sound/pci/trident/trident_main.c	Mon Mar 31 12:39:51 2003
@@ -41,7 +41,6 @@
 #include <sound/control.h>
 #include <sound/trident.h>
 #include <sound/asoundef.h>
-#include <sound/pcm_sgbuf.h>
 
 #include <asm/io.h>
 
@@ -514,6 +513,29 @@
 }
 
 /*---------------------------------------------------------------------------
+   snd_trident_write_eso_reg
+  
+   Description: This routine will write the new ESO offset
+                register to hardware.
+  
+   Paramters:   trident - pointer to target device class for 4DWave.
+                voice - synthesizer voice structure
+                ESO - new ESO value
+  
+  ---------------------------------------------------------------------------*/
+
+static void snd_trident_write_eso_reg(trident_t * trident, snd_trident_voice_t * voice, unsigned int ESO)
+{
+	voice->ESO = ESO;
+	outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
+	if (trident->device != TRIDENT_DEVICE_ID_NX) {
+		outw(voice->ESO, TRID_REG(trident, CH_DX_ESO_DELTA) + 2);
+	} else {
+		outl(((voice->Delta << 16) & 0xff000000) | (voice->ESO & 0x00ffffff), TRID_REG(trident, CH_NX_DELTA_ESO));
+	}
+}
+
+/*---------------------------------------------------------------------------
    snd_trident_write_vol_reg
   
    Description: This routine will write the new voice volume
@@ -924,7 +946,7 @@
 		evoice->spurious_threshold = voice->spurious_threshold;
 		evoice->LBA = voice->LBA;
 		evoice->CSO = 0;
-		evoice->ESO = (runtime->period_size * 2) - 1; /* in samples */
+		evoice->ESO = (runtime->period_size * 2) + 4 - 1; /* in samples */
 		evoice->CTRL = voice->CTRL;
 		evoice->FMC = 3;
 		evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1;
@@ -941,6 +963,9 @@
 		evoice->Attribute = 0;
 #endif
 		snd_trident_write_voice_regs(trident, evoice);
+		evoice->isync2 = 1;
+		evoice->isync_mark = runtime->period_size;
+		evoice->ESO = (runtime->period_size * 2) - 1;
 	}
 
 	spin_unlock(&trident->reg_lock);
@@ -984,6 +1009,8 @@
 	snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
 	unsigned int val, ESO_bytes;
 
+	snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI, return -EIO);
+
 	spin_lock(&trident->reg_lock);
 
 	// Initilize the channel and set channel Mode
@@ -992,13 +1019,11 @@
 	// Set DMA channel operation mode register
 	outb(0x54, TRID_REG(trident, LEGACY_DMAR11));
 
-	// Set channel buffer Address
-	/* FIXME: LEGACY_DMAR0 correctly set? */
+	// Set channel buffer Address, DMAR0 expects contiguous PCI memory area	
+	voice->LBA = runtime->dma_addr;
+	outl(voice->LBA, TRID_REG(trident, LEGACY_DMAR0));
 	if (voice->memblk)
 		voice->LBA = voice->memblk->offset;
-	else
-		voice->LBA = runtime->dma_addr;
-	outl(voice->LBA, TRID_REG(trident, LEGACY_DMAR0));
 
 	// set ESO
 	ESO_bytes = snd_pcm_lib_buffer_bytes(substream) - 1;
@@ -1007,7 +1032,7 @@
 	ESO_bytes++;
 
 	// Set channel sample rate, 4.12 format
-	val = ((unsigned int) 48000L << 12) / runtime->rate;
+	val = (((unsigned int) 48000L << 12) + (runtime->rate/2)) / runtime->rate;
 	outw(val, TRID_REG(trident, T4D_SBDELTA_DELTA_R));
 
 	// Set channel interrupt blk length
@@ -1034,15 +1059,13 @@
 
 	voice->Delta = snd_trident_convert_rate(runtime->rate);
 	voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);
+	voice->isync = 1;
+	voice->isync_mark = runtime->period_size;
+	voice->isync_max = runtime->buffer_size;
 
 	// Set voice parameters
 	voice->CSO = 0;
-	/* the +2 is a correction for a h/w problem. if not
-	   used, the ESO interrupt is received before the capture pointer
-	   has actually reached the ESO point. this causes errors in
-	   the mid-level code.
-	*/
-	voice->ESO = (runtime->period_size * 2) + 2 - 1;
+	voice->ESO = voice->isync_ESO = (runtime->period_size * 2) + 6 - 1;
 	voice->CTRL = snd_trident_control_mode(substream);
 	voice->FMC = 3;
 	voice->RVol = 0x7f;
@@ -1160,7 +1183,7 @@
 		evoice->spurious_threshold = voice->spurious_threshold;
 		evoice->LBA = voice->LBA;
 		evoice->CSO = 0;
-		evoice->ESO = (runtime->period_size * 2) + 8 - 1; /* in samples, 8 means correction */
+		evoice->ESO = (runtime->period_size * 2) + 20 - 1; /* in samples, 20 means correction */
 		evoice->CTRL = voice->CTRL;
 		evoice->FMC = 3;
 		evoice->GVSel = 0;
@@ -1172,6 +1195,9 @@
 		evoice->Pan = 0x7f;			/* mute */
 		evoice->Attribute = 0;
 		snd_trident_write_voice_regs(trident, evoice);
+		evoice->isync2 = 1;
+		evoice->isync_mark = runtime->period_size;
+		evoice->ESO = (runtime->period_size * 2) - 1;
 	}
 	
 	spin_unlock(&trident->reg_lock);
@@ -1234,7 +1260,7 @@
 		evoice->spurious_threshold = voice->spurious_threshold;
 		evoice->LBA = voice->LBA;
 		evoice->CSO = 0;
-		evoice->ESO = (runtime->period_size * 2) - 1; /* in samples */
+		evoice->ESO = (runtime->period_size * 2) + 4 - 1; /* in samples */
 		evoice->CTRL = voice->CTRL;
 		evoice->FMC = 3;
 		evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1;
@@ -1246,6 +1272,9 @@
 		evoice->Pan = 0x7f;			/* mute */
 		evoice->Attribute = 0;
 		snd_trident_write_voice_regs(trident, evoice);
+		evoice->isync2 = 1;
+		evoice->isync_mark = runtime->period_size;
+		evoice->ESO = (runtime->period_size * 2) - 1;
 	}
 
 	spin_unlock(&trident->reg_lock);
@@ -1348,16 +1377,20 @@
 		voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);
 
 		/* set Loop Back Address */
-		/* FIXME: LBAO?? */
 		LBAO = runtime->dma_addr;
 		if (voice->memblk)
 			voice->LBA = voice->memblk->offset;
 		else
 			voice->LBA = LBAO;
 
+		voice->isync = 1;
+		voice->isync3 = 1;
+		voice->isync_mark = runtime->period_size;
+		voice->isync_max = runtime->buffer_size;
+
 		/* set target ESO for channel */
 		RESO = runtime->buffer_size - 1;
-		voice->ESO = (runtime->period_size * 2) - 1;
+		voice->ESO = voice->isync_ESO = (runtime->period_size * 2) + 6 - 1;
 
 		/* set ctrl mode */
 		voice->CTRL = snd_trident_control_mode(substream);
@@ -1421,7 +1454,7 @@
 			evoice->spurious_threshold = voice->spurious_threshold;
 			evoice->LBA = voice->LBA;
 			evoice->CSO = 0;
-			evoice->ESO = (runtime->period_size * 2) - 1; /* in samples */
+			evoice->ESO = (runtime->period_size * 2) + 4 - 1; /* in samples */
 			evoice->CTRL = voice->CTRL;
 			evoice->FMC = 3;
 			evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1;
@@ -1433,6 +1466,9 @@
 			evoice->Pan = 0x7f;			/* mute */
 			evoice->Attribute = 0;
 			snd_trident_write_voice_regs(trident, evoice);
+			evoice->isync2 = 1;
+			evoice->isync_mark = runtime->period_size;
+			evoice->ESO = (runtime->period_size * 2) - 1;
 		}
 
 		outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS));
@@ -1499,6 +1535,8 @@
 			} else {
 				what |= 1 << (evoice->number & 0x1f);
 				whati |= 1 << (evoice->number & 0x1f);
+				if (go)
+					evoice->stimer = val;
 			}
 			if (go) {
 				voice->running = 1;
@@ -1579,7 +1617,7 @@
 
 	spin_unlock(&trident->reg_lock);
 
-	if (++cso >= runtime->buffer_size)
+	if (cso >= runtime->buffer_size)
 		cso = 0;
 
 	return cso;
@@ -1612,8 +1650,6 @@
 	if (result > 0)
 		result = runtime->buffer_size - result;
 
-	// printk("capture result = 0x%x, cso = 0x%x\n", result, cso);
-
 	return result;
 }
 
@@ -1833,6 +1869,7 @@
 		return -EAGAIN;
 	voice->spdif = 1;
 	voice->substream = substream;
+	spin_lock_irq(&trident->reg_lock);
 	trident->spdif_pcm_bits = trident->spdif_bits;
 	spin_unlock_irq(&trident->reg_lock);
 
@@ -2023,18 +2060,6 @@
 	.pointer =	snd_trident_capture_pointer,
 };
 
-static snd_pcm_ops_t snd_trident_nx_capture_ops = {
-	.open =		snd_trident_capture_open,
-	.close =	snd_trident_capture_close,
-	.ioctl =	snd_trident_ioctl,
-	.hw_params =	snd_trident_capture_hw_params,
-	.hw_free =	snd_trident_hw_free,
-	.prepare =	snd_trident_capture_prepare,
-	.trigger =	snd_trident_trigger,
-	.pointer =	snd_trident_capture_pointer,
-	.page =		snd_pcm_sgbuf_ops_page,
-};
-
 static snd_pcm_ops_t snd_trident_si7018_capture_ops = {
 	.open =		snd_trident_capture_open,
 	.close =	snd_trident_capture_close,
@@ -2080,18 +2105,6 @@
 	.pointer =	snd_trident_spdif_pointer,
 };
 
-static snd_pcm_ops_t snd_trident_nx_spdif_ops = {
-	.open =		snd_trident_spdif_open,
-	.close =	snd_trident_spdif_close,
-	.ioctl =	snd_trident_ioctl,
-	.hw_params =	snd_trident_spdif_hw_params,
-	.hw_free =	snd_trident_hw_free,
-	.prepare =	snd_trident_spdif_prepare,
-	.trigger =	snd_trident_trigger,
-	.pointer =	snd_trident_spdif_pointer,
-	.page =		snd_pcm_sgbuf_ops_page,
-};
-
 static snd_pcm_ops_t snd_trident_spdif_7018_ops = {
 	.open =		snd_trident_spdif_open,
 	.close =	snd_trident_spdif_close,
@@ -2160,24 +2173,27 @@
 
 	if (trident->tlb.entries) {
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_nx_playback_ops);
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_trident_nx_capture_ops);
 	} else {
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_playback_ops);
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-				trident->device != TRIDENT_DEVICE_ID_SI7018 ?
-				&snd_trident_capture_ops :
-				&snd_trident_si7018_capture_ops);
 	}
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+			trident->device != TRIDENT_DEVICE_ID_SI7018 ?
+			&snd_trident_capture_ops :
+			&snd_trident_si7018_capture_ops);
 
 	pcm->info_flags = 0;
 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
 	strcpy(pcm->name, "Trident 4DWave");
 	trident->pcm = pcm;
 
-	if (trident->tlb.entries)
-		snd_pcm_lib_preallocate_sg_pages_for_all(trident->pci, pcm, 64*1024, 128*1024);
-	else
+	if (trident->tlb.entries) {
+		snd_pcm_substream_t *substream;
+		for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
+			snd_pcm_lib_preallocate_sg_pages(trident->pci, substream, 64*1024, 128*1024);
+		snd_pcm_lib_preallocate_pci_pages(trident->pci, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 64*1024, 128*1024);
+	} else {
 		snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, pcm, 64*1024, 128*1024);
+	}
 
 	if (rpcm)
 		*rpcm = pcm;
@@ -2262,9 +2278,7 @@
 
 	spdif->private_data = trident;
 	spdif->private_free = snd_trident_spdif_pcm_free;
-	if (trident->tlb.entries) {
-		snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_nx_spdif_ops);
-	} else if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
+	if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
 		snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_ops);
 	} else {
 		snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_7018_ops);
@@ -2273,10 +2287,7 @@
 	strcpy(spdif->name, "Trident 4DWave IEC958");
 	trident->spdif = spdif;
 
-	if (trident->tlb.entries)
-		snd_pcm_lib_preallocate_sg_pages_for_all(trident->pci, spdif, 64*1024, 128*1024);
-	else
-		snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, spdif, 64*1024, 128*1024);
+	snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, spdif, 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = spdif;
@@ -2947,6 +2958,7 @@
 	_ac97.read = snd_trident_codec_read;
 	_ac97.private_data = trident;
 	trident->ac97_detect = 1;
+
       __again:
 	if ((err = snd_ac97_mixer(trident->card, &_ac97, &trident->ac97)) < 0) {
 		if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
@@ -2958,6 +2970,24 @@
 		}
 		return err;
 	}
+	
+	/* secondary codec? */
+	if (trident->device == TRIDENT_DEVICE_ID_SI7018 &&
+	    (inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_PRIMARY_READY) != 0) {
+		_ac97.num = 1;
+		err = snd_ac97_mixer(trident->card, &_ac97, &trident->ac97_sec);
+		if (err < 0)
+			snd_printk("SI7018: the secondary codec - invalid access\n");
+#if 0	// only for my testing purpose --jk
+		{
+			ac97_t *mc97;
+			err = snd_ac97_modem(trident->card, &_ac97, &mc97);
+			if (err < 0)
+				snd_printk("snd_ac97_modem returned error %i\n", err);
+		}
+#endif
+	}
+	
 	trident->ac97_detect = 0;
 
 	if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
@@ -3012,17 +3042,29 @@
 		kctl->put(kctl, &uctl);
 	}
 	if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
+
 		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_control, trident))) < 0)
 			return err;
+		if (trident->ac97->ext_id & AC97_EI_SPDIF)
+			kctl->id.index++;
+		if (trident->ac97_sec && (trident->ac97_sec->ext_id & AC97_EI_SPDIF))
+			kctl->id.index++;
+		idx = kctl->id.index;
 		kctl->put(kctl, &uctl);
+
 		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_default, trident))) < 0)
 			return err;
+		kctl->id.index = idx;
 		kctl->id.device = pcm_spdif_device;
+
 		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_mask, trident))) < 0)
 			return err;
+		kctl->id.index = idx;
 		kctl->id.device = pcm_spdif_device;
+
 		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_stream, trident))) < 0)
 			return err;
+		kctl->id.index = idx;
 		kctl->id.device = pcm_spdif_device;
 		trident->spdif_pcm_ctl = kctl;
 	}
@@ -3181,6 +3223,12 @@
 		goto __si7018_retry;
 	}
       __si7018_ok:
+	/* wait for the second codec */
+	do {
+		if ((inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_SECONDARY_READY) != 0)
+			break;
+		do_delay(trident);
+	} while (time_after_eq(end_time, jiffies));
 	/* enable 64 channel mode */
 	outl(BANK_B_EN, TRID_REG(trident, T4D_LFO_GC_CIR));
 	return 0;
@@ -3640,7 +3688,7 @@
 static void snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	trident_t *trident = snd_magic_cast(trident_t, dev_id, return);
-	unsigned int audio_int, chn_int, stimer, channel, mask;
+	unsigned int audio_int, chn_int, stimer, channel, mask, tmp;
 	int delta;
 	snd_trident_voice_t *voice;
 
@@ -3679,16 +3727,42 @@
 				continue;
 			}
 			voice->stimer = stimer;
+			if (voice->isync) {
+				if (!voice->isync3) {
+					tmp = inw(TRID_REG(trident, T4D_SBBL_SBCL));
+					if (trident->bDMAStart & 0x40)
+						tmp >>= 1;
+					if (tmp > 0)
+						tmp = voice->isync_max - tmp;
+				} else {
+					tmp = inl(TRID_REG(trident, NX_SPCTRL_SPCSO)) & 0x00ffffff;
+				}
+				if (tmp < voice->isync_mark) {
+					if (tmp > 0x10)
+						tmp = voice->isync_ESO - 7;
+					else
+						tmp = voice->isync_ESO + 2;
+					/* update ESO for IRQ voice to preserve sync */
+					snd_trident_stop_voice(trident, voice->number);
+					snd_trident_write_eso_reg(trident, voice, tmp);
+					snd_trident_start_voice(trident, voice->number);
+				}
+			} else if (voice->isync2) {
+				voice->isync2 = 0;
+				/* write original ESO and update CSO for IRQ voice to preserve sync */
+				snd_trident_stop_voice(trident, voice->number);
+				snd_trident_write_cso_reg(trident, voice, voice->isync_mark);
+				snd_trident_write_eso_reg(trident, voice, voice->ESO);
+				snd_trident_start_voice(trident, voice->number);
+			}
+#if 0
 			if (voice->extra) {
 				/* update CSO for extra voice to preserve sync */
 				snd_trident_stop_voice(trident, voice->extra->number);
 				snd_trident_write_cso_reg(trident, voice->extra, 0);
 				snd_trident_start_voice(trident, voice->extra->number);
-			} else if (voice->spdif) {
-				snd_trident_stop_voice(trident, voice->number);
-				snd_trident_write_cso_reg(trident, voice, 0);
-				snd_trident_start_voice(trident, voice->number);
 			}
+#endif
 			spin_unlock(&trident->reg_lock);
 			snd_pcm_period_elapsed(voice->substream);
 			spin_lock(&trident->reg_lock);
diff -urN linux-2.5.65-bk1/sound/pci/trident/trident_memory.c linux-2.5.65-bk2/sound/pci/trident/trident_memory.c
--- linux-2.5.65-bk1/sound/pci/trident/trident_memory.c	Mon Mar 17 13:44:20 2003
+++ linux-2.5.65-bk2/sound/pci/trident/trident_memory.c	Mon Mar 31 12:39:51 2003
@@ -28,7 +28,6 @@
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/trident.h>
-#include <sound/pcm_sgbuf.h>
 
 /* page arguments of these two macros are Trident page (4096 bytes), not like
  * aligned pages in others
@@ -181,23 +180,26 @@
 }
 
 /*
- * page allocation for DMA
+ * page allocation for DMA (Scatter-Gather version)
  */
-snd_util_memblk_t *
-snd_trident_alloc_pages(trident_t *trident, snd_pcm_substream_t *substream)
+static snd_util_memblk_t *
+snd_trident_alloc_sg_pages(trident_t *trident, snd_pcm_substream_t *substream)
 {
 	snd_util_memhdr_t *hdr;
 	snd_util_memblk_t *blk;
+	snd_pcm_runtime_t *runtime = substream->runtime;
 	int idx, page;
-	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, _snd_pcm_substream_sgbuf(substream), return NULL);
+	struct snd_sg_buf *sgbuf = runtime->dma_private;
 
-	snd_assert(trident != NULL, return NULL);
-	snd_assert(sgbuf->size > 0 && sgbuf->size < SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
+	snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG, return NULL);
+	snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
 	hdr = trident->tlb.memhdr;
 	snd_assert(hdr != NULL, return NULL);
 
+	
+
 	down(&hdr->block_mutex);
-	blk = search_empty(hdr, sgbuf->size);
+	blk = search_empty(hdr, runtime->dma_bytes);
 	if (blk == NULL) {
 		up(&hdr->block_mutex);
 		return NULL;
@@ -225,6 +227,61 @@
 	return blk;
 }
 
+/*
+ * page allocation for DMA (contiguous version)
+ */
+static snd_util_memblk_t *
+snd_trident_alloc_cont_pages(trident_t *trident, snd_pcm_substream_t *substream)
+{
+	snd_util_memhdr_t *hdr;
+	snd_util_memblk_t *blk;
+	int page;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	dma_addr_t addr;
+	unsigned long ptr;
+
+	snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI, return NULL);
+	snd_assert(runtime->dma_bytes> 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL);
+	hdr = trident->tlb.memhdr;
+	snd_assert(hdr != NULL, return NULL);
+
+	down(&hdr->block_mutex);
+	blk = search_empty(hdr, runtime->dma_bytes);
+	if (blk == NULL) {
+		up(&hdr->block_mutex);
+		return NULL;
+	}
+			   
+	/* set TLB entries */
+	addr = runtime->dma_addr;
+	ptr = (unsigned long)runtime->dma_area;
+	for (page = firstpg(blk); page <= lastpg(blk); page++,
+	     ptr += SNDRV_TRIDENT_PAGE_SIZE, addr += SNDRV_TRIDENT_PAGE_SIZE) {
+		if (! is_valid_page(addr)) {
+			__snd_util_mem_free(hdr, blk);
+			up(&hdr->block_mutex);
+			return NULL;
+		}
+		set_tlb_bus(trident, page, ptr, addr);
+	}
+	up(&hdr->block_mutex);
+	return blk;
+}
+
+/*
+ * page allocation for DMA
+ */
+snd_util_memblk_t *
+snd_trident_alloc_pages(trident_t *trident, snd_pcm_substream_t *substream)
+{
+	snd_assert(trident != NULL, return NULL);
+	snd_assert(substream != NULL, return NULL);
+	if (substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG)
+		return snd_trident_alloc_sg_pages(trident, substream);
+	else
+		return snd_trident_alloc_cont_pages(trident, substream);
+}
+
 
 /*
  * release DMA buffer from page table
diff -urN linux-2.5.65-bk1/sound/pci/trident/trident_synth.c linux-2.5.65-bk2/sound/pci/trident/trident_synth.c
--- linux-2.5.65-bk1/sound/pci/trident/trident_synth.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/sound/pci/trident/trident_synth.c	Mon Mar 31 12:39:51 2003
@@ -600,7 +600,7 @@
 		size <<= 1;
 
 	trident->synth.current_size -= size;
-	if (trident->synth.current_size < 0)	/* shouldnt need this check... */
+	if (trident->synth.current_size < 0)	/* shouldn't need this check... */
 		trident->synth.current_size = 0;
 
 	return 0;
@@ -909,7 +909,7 @@
 						   SNDRV_SEQ_PORT_TYPE_MIDI_GS |
 						   SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
 						   SNDRV_SEQ_PORT_TYPE_SYNTH,
-						   16,
+						   16, 0,
 						   name);
 	if (p->chset->port < 0) {
 		result = p->chset->port;
diff -urN linux-2.5.65-bk1/sound/pci/via82xx.c linux-2.5.65-bk2/sound/pci/via82xx.c
--- linux-2.5.65-bk1/sound/pci/via82xx.c	Mon Mar 17 13:44:41 2003
+++ linux-2.5.65-bk2/sound/pci/via82xx.c	Mon Mar 31 12:39:51 2003
@@ -52,7 +52,6 @@
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
-#include <sound/pcm_sgbuf.h>
 #include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <sound/ac97_codec.h>
@@ -599,12 +598,12 @@
 		status &= (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG);
 		if (! status)
 			continue;
-		outb(status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */
 		if (viadev->substream && viadev->running) {
 			spin_unlock(&chip->reg_lock);
 			snd_pcm_period_elapsed(viadev->substream);
 			spin_lock(&chip->reg_lock);
 		}
+		outb(status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */
 	}
 	spin_unlock(&chip->reg_lock);
 }
@@ -820,6 +819,7 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
+	snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
 	via686_setup_format(chip, viadev, runtime);
 	return 0;
 }
@@ -912,15 +912,15 @@
 	fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
 	fmt |= runtime->channels << 4;
 	outb(fmt, VIADEV_REG(viadev, OFS_MULTPLAY_FORMAT));
-	/* set sample number to slot 3, 4, 7, 8, 6, 9 */
+	/* set sample number to slot 3, 4, 7, 8, 6, 9 (for VIA8233/C,8235) */
 	/* corresponding to FL, FR, RL, RR, C, LFE ?? */
 	switch (runtime->channels) {
 	case 1: slots = (1<<0) | (1<<4); break;
 	case 2: slots = (1<<0) | (2<<4); break;
 	case 3: slots = (1<<0) | (2<<4) | (5<<8); break;
 	case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
-	case 5: slots = (1<<0) | (2<<4) | (5<<8) | (3<<12) | (4<<16); break;
-	case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
+	case 5: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12) | (5<<16); break;
+	case 6: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12) | (5<<16) | (6<<20); break;
 	default: slots = 0; break;
 	}
 	/* STOP index is never reached */
@@ -1438,7 +1438,7 @@
 }
 
 static struct ac97_quirk ac97_quirks[] = {
-	{ 0x1106, 0x4161, AC97_TUNE_HP_ONLY }, /* ASRock K7VT2 */
+	{ 0x1106, 0x4161, "ASRock K7VT2", AC97_TUNE_HP_ONLY },
 	{ } /* terminator */
 };
 
@@ -1457,7 +1457,7 @@
 	if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
 		return err;
 
-	snd_ac97_tune_hardware(&chip->ac97, chip->pci, ac97_quirks);
+	snd_ac97_tune_hardware(chip->ac97, chip->pci, ac97_quirks);
 
 	if (chip->chip_type != TYPE_VIA686) {
 		/* use slot 10/11 */
diff -urN linux-2.5.65-bk1/sound/synth/emux/emux_seq.c linux-2.5.65-bk2/sound/synth/emux/emux_seq.c
--- linux-2.5.65-bk1/sound/synth/emux/emux_seq.c	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/sound/synth/emux/emux_seq.c	Mon Mar 31 12:39:51 2003
@@ -176,7 +176,8 @@
 	}
 
 	p->chset.port = snd_seq_event_port_attach(emu->client, callback,
-						  cap, type, max_channels, name);
+						  cap, type, max_channels,
+						  emu->max_voices, name);
 
 	return p;
 }
diff -urN linux-2.5.65-bk1/sound/usb/usbaudio.c linux-2.5.65-bk2/sound/usb/usbaudio.c
--- linux-2.5.65-bk1/sound/usb/usbaudio.c	Mon Mar 17 13:44:21 2003
+++ linux-2.5.65-bk2/sound/usb/usbaudio.c	Mon Mar 31 12:39:51 2003
@@ -584,14 +584,14 @@
  * unlink active urbs.
  * return the number of active urbs.
  */
-static int deactivate_urbs(snd_usb_substream_t *subs)
+static int deactivate_urbs(snd_usb_substream_t *subs, int force)
 {
 	unsigned int i;
 	int alive;
 
 	subs->running = 0;
 
-	if (subs->stream->chip->shutdown) /* to be sure... */
+	if (!force && subs->stream->chip->shutdown) /* to be sure... */
 		return 0;
 
 #ifndef SND_USB_ASYNC_UNLINK
@@ -669,7 +669,7 @@
 
  __error:
 	// snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
-	deactivate_urbs(subs);
+	deactivate_urbs(subs, 0);
 	return -EPIPE;
 }
 
@@ -730,7 +730,7 @@
 		err = start_urbs(subs, substream->runtime);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		err = deactivate_urbs(subs);
+		err = deactivate_urbs(subs, 0);
 		break;
 	default:
 		err = -EINVAL;
@@ -758,12 +758,12 @@
 /*
  * release a substream
  */
-static void release_substream_urbs(snd_usb_substream_t *subs)
+static void release_substream_urbs(snd_usb_substream_t *subs, int force)
 {
 	int i;
 
 	/* stop urbs (to be sure) */
-	if (deactivate_urbs(subs) > 0)
+	if (deactivate_urbs(subs, force) > 0)
 		wait_clear_urbs(subs);
 
 	for (i = 0; i < MAX_URBS; i++)
@@ -869,13 +869,13 @@
 			/* allocate a capture buffer per urb */
 			u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL);
 			if (! u->buf) {
-				release_substream_urbs(subs);
+				release_substream_urbs(subs, 0);
 				return -ENOMEM;
 			}
 		}
 		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
 		if (! u->urb) {
-			release_substream_urbs(subs);
+			release_substream_urbs(subs, 0);
 			return -ENOMEM;
 		}
 		u->urb->dev = subs->dev;
@@ -895,7 +895,7 @@
 			u->packets = NRPACKS;
 			u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
 			if (! u->urb) {
-				release_substream_urbs(subs);
+				release_substream_urbs(subs, 0);
 				return -ENOMEM;
 			}
 			u->urb->transfer_buffer = subs->syncbuf + i * NRPACKS * 3;
@@ -1051,7 +1051,7 @@
 	}
 
 	/* create a data pipe */
-	ep = get_endpoint(alts, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK;
 	if (is_playback)
 		subs->datapipe = usb_sndisocpipe(dev, ep);
 	else
@@ -1062,9 +1062,16 @@
 	subs->fill_max = 0;
 
 	/* we need a sync pipe in async OUT or adaptive IN mode */
-	attr = get_endpoint(alts, 0)->bmAttributes & EP_ATTR_MASK;
+	attr = fmt->ep_attr & EP_ATTR_MASK;
 	if ((is_playback && attr == EP_ATTR_ASYNC) ||
 	    (! is_playback && attr == EP_ATTR_ADAPTIVE)) {
+		/*
+		 * QUIRK: plantronics headset has adaptive-in
+		 * although it's really not...
+		 */
+		if (dev->descriptor.idVendor == 0x047f &&
+		    dev->descriptor.idProduct == 0x0ca1)
+			goto _ok;
 		/* check endpoint */
 		if (altsd->bNumEndpoints < 2 ||
 		    get_endpoint(alts, 1)->bmAttributes != 0x01 ||
@@ -1088,6 +1095,7 @@
 		subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
 	}
 
+ _ok:
 	if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0 ||
 	    (err = init_usb_sample_rate(dev, subs->interface, alts, fmt,
 					runtime->rate)) < 0)
@@ -1140,7 +1148,7 @@
 	snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data;
 	int err;
 
-	release_substream_urbs(subs);
+	release_substream_urbs(subs, 0);
 	if ((err = set_format(subs, runtime)) < 0)
 		return err;
 
@@ -1189,7 +1197,7 @@
 
 	/* check the format */
 	if (! snd_mask_test(fmts, fp->format)) {
-		printk(KERN_DEBUG "   > check: no supported format %d\n", fp->format);
+		hwc_debug("   > check: no supported format %d\n", fp->format);
 		return 0;
 	}
 	/* check the channels */
@@ -1477,7 +1485,7 @@
 	snd_usb_stream_t *as = snd_pcm_substream_chip(substream);
 	snd_usb_substream_t *subs = &as->substream[direction];
 
-	release_substream_urbs(subs);
+	release_substream_urbs(subs, 0);
 	if (subs->interface >= 0)
 		usb_set_interface(subs->dev, subs->interface, 0);
 	subs->pcm_substream = NULL;
@@ -1548,15 +1556,11 @@
 
 /*
  * parse descriptor buffer and return the pointer starting the given
- * descriptor type and interface.
- * if altsetting is not -1, seek the buffer until the matching alternate
- * setting is found.
+ * descriptor type.
  */
-void *snd_usb_find_desc(void *descstart, int desclen, void *after, 
-			u8 dtype, int iface, int altsetting)
+void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype)
 {
 	u8 *p, *end, *next;
-	int ifc = -1, as = -1;
 
 	p = descstart;
 	end = p + desclen;
@@ -1566,15 +1570,7 @@
 		next = p + p[0];
 		if (next > end)
 			return NULL;
-		if (p[1] == USB_DT_INTERFACE) {
-			/* minimum length of interface descriptor */
-			if (p[0] < 9)
-				return NULL;
-			ifc = p[2];
-			as = p[3];
-		}
-		if (p[1] == dtype && (!after || (void *)p > after) &&
-		    (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) {
+		if (p[1] == dtype && (!after || (void *)p > after)) {
 			return p;
 		}
 		p = next;
@@ -1585,12 +1581,12 @@
 /*
  * find a class-specified interface descriptor with the given subtype.
  */
-void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype, int iface, int altsetting)
+void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype)
 {
 	unsigned char *p = after;
 
 	while ((p = snd_usb_find_desc(buffer, buflen, p,
-				      USB_DT_CS_INTERFACE, iface, altsetting)) != NULL) {
+				      USB_DT_CS_INTERFACE)) != NULL) {
 		if (p[0] >= 3 && p[2] == dsubtype)
 			return p;
 	}
@@ -1651,7 +1647,7 @@
 			    fp->endpoint & USB_DIR_IN ? "IN" : "OUT",
 			    sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]);
 		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) {
-			snd_iprintf(buffer, "    Rates: %d - %d (continous)\n",
+			snd_iprintf(buffer, "    Rates: %d - %d (continuous)\n",
 				    fp->rate_min, fp->rate_max);
 		} else {
 			unsigned int i;
@@ -1942,7 +1938,7 @@
 }
 
 
-static int parse_audio_endpoints(snd_usb_audio_t *chip, unsigned char *buffer, int buflen, int iface_no)
+static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
 {
 	struct usb_device *dev;
 	struct usb_host_config *config;
@@ -1963,7 +1959,8 @@
 		alts = &iface->altsetting[i];
 		altsd = get_iface_desc(alts);
 		/* skip invalid one */
-		if (altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+		if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
+		     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
 		    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING ||
 		    altsd->bNumEndpoints < 1)
 			continue;
@@ -1977,7 +1974,7 @@
 		altno = altsd->bAlternateSetting;
 
 		/* get audio formats */
-		fmt = snd_usb_find_csint_desc(buffer, buflen, NULL, AS_GENERAL, iface_no, altno);
+		fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL);
 		if (!fmt) {
 			snd_printk(KERN_ERR "%d:%u:%d : AS_GENERAL descriptor not found\n",
 				   dev->devnum, iface_no, altno);
@@ -1993,7 +1990,7 @@
 		format = (fmt[6] << 8) | fmt[5]; /* remember the format value */
 			
 		/* get format type */
-		fmt = snd_usb_find_csint_desc(buffer, buflen, NULL, FORMAT_TYPE, iface_no, altno);
+		fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, FORMAT_TYPE);
 		if (!fmt) {
 			snd_printk(KERN_ERR "%d:%u:%d : no FORMAT_TYPE desc\n", 
 				   dev->devnum, iface_no, altno);
@@ -2023,7 +2020,7 @@
 			continue;
 		}
 
-		csep = snd_usb_find_desc(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, iface_no, altno);
+		csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
 		if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
 			snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n", 
 				   dev->devnum, iface_no, altno);
@@ -2111,17 +2108,19 @@
 /*
  * parse audio control descriptor and create pcm/midi streams
  */
-static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
-				  unsigned char *buffer, int buflen)
+static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif)
 {
 	struct usb_device *dev = chip->dev;
 	struct usb_host_config *config;
+	struct usb_host_interface *host_iface;
 	struct usb_interface *iface;
 	unsigned char *p1;
 	int i, j;
 
 	/* find audiocontrol interface */
-	if (!(p1 = snd_usb_find_csint_desc(buffer, buflen, NULL, HEADER, ctrlif, -1))) {
+	config = dev->actconfig;
+	host_iface = &config->interface[ctrlif].altsetting[0];
+	if (!(p1 = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, NULL, HEADER))) {
 		snd_printk(KERN_ERR "cannot find HEADER\n");
 		return -EINVAL;
 	}
@@ -2133,7 +2132,6 @@
 	/*
 	 * parse all USB audio streaming interfaces
 	 */
-	config = dev->actconfig;
 	for (i = 0; i < p1[7]; i++) {
 		struct usb_host_interface *alts;
 		struct usb_interface_descriptor *altsd;
@@ -2150,7 +2148,8 @@
 		}
 		alts = &iface->altsetting[0];
 		altsd = get_iface_desc(alts);
-		if (altsd->bInterfaceClass == USB_CLASS_AUDIO &&
+		if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
+		     altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
 		    altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
 			if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) {
 				snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
@@ -2159,13 +2158,14 @@
 			usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
 			continue;
 		}
-		if (altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+		if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
+		     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
 		    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) {
 			snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, altsd->bInterfaceClass);
 			/* skip non-supported classes */
 			continue;
 		}
-		if (! parse_audio_endpoints(chip, buffer, buflen, j)) {
+		if (! parse_audio_endpoints(chip, j)) {
 			usb_set_interface(dev, j, 0); /* reset the current interface */
 			usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
 		}
@@ -2205,6 +2205,40 @@
 	return 0;
 }
 
+/*
+ * create a stream for an interface with proper descriptors
+ */
+static int create_standard_interface_quirk(snd_usb_audio_t *chip,
+					   struct usb_interface *iface)
+{
+	struct usb_host_interface *alts;
+	struct usb_interface_descriptor *altsd;
+	int err;
+
+	alts = &iface->altsetting[0];
+	altsd = get_iface_desc(alts);
+	switch (altsd->bInterfaceSubClass) {
+	case USB_SUBCLASS_AUDIO_STREAMING:
+		err = parse_audio_endpoints(chip, altsd->bInterfaceNumber);
+		if (!err)
+			usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); /* reset the current interface */
+		break;
+	case USB_SUBCLASS_MIDI_STREAMING:
+		err = snd_usb_create_midi_interface(chip, iface, NULL);
+		break;
+	default:
+		snd_printk(KERN_ERR "if %d: non-supported subclass %d\n",
+			   altsd->bInterfaceNumber, altsd->bInterfaceSubClass);
+		return -ENODEV;
+	}
+	if (err < 0) {
+		snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
+			   altsd->bInterfaceNumber, err);
+		return err;
+	}
+	return 0;
+}
+
 static int snd_usb_create_quirk(snd_usb_audio_t *chip,
 				struct usb_interface *iface,
 				const snd_usb_audio_quirk_t *quirk);
@@ -2288,6 +2322,8 @@
 		return create_composite_quirk(chip, iface, quirk);
 	case QUIRK_AUDIO_FIXED_ENDPOINT:
 		return create_fixed_stream_quirk(chip, iface, quirk);
+	case QUIRK_STANDARD_INTERFACE:
+		return create_standard_interface_quirk(chip, iface);
 	default:
 		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 		return -ENXIO;
@@ -2405,42 +2441,6 @@
 
 
 /*
- * allocate and get description buffer
- * must be freed later.
- */
-static int alloc_desc_buffer(struct usb_device *dev, int index, unsigned char **bufptr)
-{
-	int err, buflen;
-	unsigned char buf[8];
-	unsigned char *buffer;
-
-	*bufptr = 0;
-	err = usb_get_descriptor(dev, USB_DT_CONFIG, index, buf, 8);
-	if (err < 0) {
-		snd_printk(KERN_ERR "%d:%d: cannot get first 8 bytes\n", index, dev->devnum);
-		return err;
-	}
-	if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
-		snd_printk(KERN_ERR "%d:%d: invalid config desc\n", index, dev->devnum);
-		return -EINVAL;
-	}
-	buflen = combine_word(&buf[2]);
-	if (!(buffer = kmalloc(buflen, GFP_KERNEL))) {
-		snd_printk(KERN_ERR "cannot malloc descriptor (size = %d)\n", buflen);
-		return -ENOMEM;
-	}
-	err = usb_get_descriptor(dev, USB_DT_CONFIG, index, buffer, buflen);
-	if (err < 0) {
-		snd_printk(KERN_ERR "%d:%d: cannot get DT_CONFIG: error %d\n", index, dev->devnum, err);
-		kfree(buffer);
-		return err;
-	}
-	*bufptr = buffer;
-	return buflen;
-}
-
-
-/*
  * probe the active usb device
  *
  * note that this can be called multiple times per a device, when it
@@ -2532,20 +2532,10 @@
 
 	if (err > 0) {
 		/* create normal USB audio interfaces */
-		unsigned char *buffer;
-		unsigned int index;
-		int buflen;
-
-		index = dev->actconfig - config;
-		buflen = alloc_desc_buffer(dev, index, &buffer);
-		if (buflen <= 0)
-			goto __error;
-		if (snd_usb_create_streams(chip, ifnum, buffer, buflen) < 0 ||
-		    snd_usb_create_mixer(chip, ifnum, buffer, buflen) < 0) {
-			kfree(buffer);
+		if (snd_usb_create_streams(chip, ifnum) < 0 ||
+		    snd_usb_create_mixer(chip, ifnum) < 0) {
 			goto __error;
 		}
-		kfree(buffer);
 	}
 
 	/* we are allowed to call snd_card_register() many times */
@@ -2595,7 +2585,8 @@
 				subs = &as->substream[idx];
 				if (!subs->num_formats)
 					continue;
-				release_substream_urbs(subs);
+				release_substream_urbs(subs, 1);
+				subs->interface = -1;
 			}
 		}
 		/* release the midi resources */
diff -urN linux-2.5.65-bk1/sound/usb/usbaudio.h linux-2.5.65-bk2/sound/usb/usbaudio.h
--- linux-2.5.65-bk1/sound/usb/usbaudio.h	Mon Mar 17 13:44:13 2003
+++ linux-2.5.65-bk2/sound/usb/usbaudio.h	Mon Mar 31 12:39:51 2003
@@ -146,6 +146,7 @@
 /*
  * Information about devices with broken descriptors
  */
+
 #define QUIRK_ANY_INTERFACE -1
 
 #define QUIRK_MIDI_FIXED_ENDPOINT	0
@@ -153,6 +154,7 @@
 #define QUIRK_MIDI_MIDIMAN		2
 #define QUIRK_COMPOSITE			3
 #define QUIRK_AUDIO_FIXED_ENDPOINT	4
+#define QUIRK_STANDARD_INTERFACE	5
 
 #define QUIRK_BOOT_MASK			0x80
 #define QUIRK_BOOT_EXTIGY		(QUIRK_BOOT_MASK | 0)
@@ -185,6 +187,8 @@
 
 /* for QUIRK_AUDIO_FIXED_ENDPOINT, data points to an audioformat structure */
 
+/* for QUIRK_STANDARD_INTERFACE, data is NULL */
+
 /*
  */
 
@@ -194,10 +198,10 @@
 
 unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size);
 
-void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype, int iface, int altsetting);
-void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype, int iface, int altsetting);
+void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype);
+void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype);
 
-int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffer, int buflen);
+int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif);
 
 int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk);
 void snd_usbmidi_disconnect(struct list_head *p);
diff -urN linux-2.5.65-bk1/sound/usb/usbmidi.c linux-2.5.65-bk2/sound/usb/usbmidi.c
--- linux-2.5.65-bk1/sound/usb/usbmidi.c	Mon Mar 17 13:44:43 2003
+++ linux-2.5.65-bk2/sound/usb/usbmidi.c	Mon Mar 31 12:39:51 2003
@@ -131,7 +131,7 @@
 {
 	int err = usb_submit_urb(urb, flags);
 	if (err < 0 && err != -ENODEV)
-		printk(KERN_ERR "snd-usb-midi: usb_submit_urb: %d\n", err);
+		snd_printk(KERN_ERR "usb_submit_urb: %d\n", err);
 	return err;
 }
 
@@ -146,7 +146,7 @@
 	    status == -EILSEQ ||
 	    status == -ETIMEDOUT)
 		return -ENODEV; /* device removed */
-	printk(KERN_ERR "snd-usb-midi: urb status %d\n", status);
+	snd_printk(KERN_ERR "urb status %d\n", status);
 	return 0; /* continue */
 }
 
@@ -435,8 +435,10 @@
 					port = &umidi->endpoints[i].out->ports[j];
 					break;
 				}
-	if (!port)
+	if (!port) {
+		snd_BUG();
 		return -ENXIO;
+	}
 	substream->runtime->private_data = port;
 	port->state = STATE_UNKNOWN;
 	return 0;
@@ -526,6 +528,8 @@
 	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
 		return NULL;
 
+	snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n",
+		    intfd->bAlternateSetting);
 	usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
 			  intfd->bAlternateSetting);
 	return get_endpoint(hostif, 1);
@@ -774,8 +778,8 @@
 			}
 		}
 	}
-	printk(KERN_INFO "snd-usb-midi: created %d output and %d input ports\n",
-	       out_ports, in_ports);
+	snd_printdd(KERN_INFO "created %d output and %d input ports\n",
+		    out_ports, in_ports);
 	return 0;
 }
 
@@ -804,10 +808,10 @@
 	    ms_header->bLength >= 7 &&
 	    ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
 	    ms_header->bDescriptorSubtype == HEADER)
-		printk(KERN_INFO "snd-usb-midi: MIDIStreaming version %02x.%02x\n",
-		       ms_header->bcdMSC[1], ms_header->bcdMSC[0]);
+		snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n",
+			    ms_header->bcdMSC[1], ms_header->bcdMSC[0]);
 	else
-		printk(KERN_WARNING "snd-usb-midi: MIDIStreaming interface descriptor not found\n");
+		snd_printk(KERN_WARNING "MIDIStreaming interface descriptor not found\n");
 
 	epidx = 0;
 	for (i = 0; i < intfd->bNumEndpoints; ++i) {
@@ -824,25 +828,25 @@
 		if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
 			if (endpoints[epidx].out_ep) {
 				if (++epidx >= MIDI_MAX_ENDPOINTS) {
-					printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
+					snd_printk(KERN_WARNING "too many endpoints\n");
 					break;
 				}
 			}
 			endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 			endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
-			printk(KERN_INFO "snd-usb-midi: EP %02X: %d jack(s)\n",
-			       ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
+			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
+				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
 		} else {
 			if (endpoints[epidx].in_ep) {
 				if (++epidx >= MIDI_MAX_ENDPOINTS) {
-					printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
+					snd_printk(KERN_WARNING "too many endpoints\n");
 					break;
 				}
 			}
 			endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 			endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
-			printk(KERN_INFO "snd-usb-midi: EP %02X: %d jack(s)\n",
-			       ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
+			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
+				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
 		}
 	}
 	return 0;
diff -urN linux-2.5.65-bk1/sound/usb/usbmixer.c linux-2.5.65-bk2/sound/usb/usbmixer.c
--- linux-2.5.65-bk1/sound/usb/usbmixer.c	Mon Mar 17 13:43:50 2003
+++ linux-2.5.65-bk2/sound/usb/usbmixer.c	Mon Mar 31 12:39:51 2003
@@ -182,7 +182,7 @@
 
 	p = NULL;
 	while ((p = snd_usb_find_desc(state->buffer, state->buflen, p,
-				      USB_DT_CS_INTERFACE, state->ctrlif, -1)) != NULL) {
+				      USB_DT_CS_INTERFACE)) != NULL) {
 		if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
 			return p;
 	}
@@ -1462,20 +1462,21 @@
  *
  * walk through all OUTPUT_TERMINAL descriptors to search for mixers
  */
-int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffer, int buflen)
+int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
 {
 	unsigned char *desc;
 	mixer_build_t state;
 	int err;
 	const struct usbmix_ctl_map *map;
 	struct usb_device_descriptor *dev = &chip->dev->descriptor;
+	struct usb_host_interface *hostif = &chip->dev->actconfig->interface[ctrlif].altsetting[0];
 
 	strcpy(chip->card->mixername, "USB Mixer");
 
 	memset(&state, 0, sizeof(state));
 	state.chip = chip;
-	state.buffer = buffer;
-	state.buflen = buflen;
+	state.buffer = hostif->extra;
+	state.buflen = hostif->extralen;
 	state.ctrlif = ctrlif;
 	state.vendor = dev->idVendor;
 	state.product = dev->idProduct;
@@ -1489,7 +1490,7 @@
 	}
 
 	desc = NULL;
-	while ((desc = snd_usb_find_csint_desc(buffer, buflen, desc, OUTPUT_TERMINAL, ctrlif, -1)) != NULL) {
+	while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) {
 		if (desc[0] < 9)
 			continue; /* invalid descriptor? */
 		set_bit(desc[3], state.unitbitmap);  /* mark terminal ID as visited */
diff -urN linux-2.5.65-bk1/sound/usb/usbquirks.h linux-2.5.65-bk2/sound/usb/usbquirks.h
--- linux-2.5.65-bk1/sound/usb/usbquirks.h	Mon Mar 17 13:44:04 2003
+++ linux-2.5.65-bk2/sound/usb/usbquirks.h	Mon Mar 31 12:39:51 2003
@@ -26,6 +26,11 @@
  * In a perfect world, this file would be empty.
  */
 
+/*
+ * Use this for devices where other interfaces are standard compliant,
+ * to prevent the quirk being applied to those interfaces. (To work with
+ * hotplugging, bDeviceClass must be set to USB_CLASS_PER_INTERFACE.)
+ */
 #define USB_DEVICE_VENDOR_SPEC(vend, prod) \
 	.match_flags = USB_DEVICE_ID_MATCH_VENDOR | \
 		       USB_DEVICE_ID_MATCH_PRODUCT | \
@@ -226,16 +231,10 @@
 },
 
 /*
- * Once upon a time people thought, "Wouldn't it be nice if there was a
- * standard for USB MIDI devices, so that device drivers would not be forced
- * to know about the quirks of specific devices?"  So Roland went ahead and
- * wrote the USB Device Class Definition for MIDI Devices, and the USB-IF
- * endorsed it, and now everybody designing USB MIDI devices does so in
- * agreement with this standard (or at least tries to).
+ * Roland/RolandED/Edirol devices
  *
- * And if you prefer a happy end, you can imagine that Roland devices set a
- * good example. Instead of being completely fucked up due to the lack of
- * class-specific descriptors.
+ * The USB MIDI Specification has been written by Roland,
+ * but a 100% conforming Roland device has yet to be found.
  */
 {
 	USB_DEVICE(0x0582, 0x0000),
@@ -507,15 +506,33 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0025),
+	/*
+	 * This quirk is for the "Advanced Driver" mode. If off, the UA-20
+	 * has ID 0x0026 and is standard compliant, but has only 16-bit PCM
+	 * and no MIDI.
+	 */
+	USB_DEVICE(0x0582, 0x0025),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "UA-20",
-		.ifnum = 3,
-		.type = QUIRK_MIDI_FIXED_ENDPOINT,
-		.data = & (const snd_usb_midi_endpoint_info_t) {
-			.out_cables = 0x0001,
-			.in_cables  = 0x0001
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = & (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = -1
+			}
 		}
 	}
 },
@@ -639,6 +656,24 @@
 	}
 },
 {
+	/*
+	 * For hardware revision 1.05; in the later revisions (1.10 and
+	 * 1.21), 0x1031 is the ID for the device without firmware.
+	 * Thanks to Olaf Giesbrecht <Olaf_Giesbrecht@yahoo.de>
+	 */
+	USB_DEVICE_VER(0x0763, 0x1031, 0x0100, 0x0109),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "M-Audio",
+		.product_name = "MidiSport 8x8",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_MIDI_MIDIMAN,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x01ff,
+			.in_cables  = 0x01ff
+		}
+	}
+},
+{
 	USB_DEVICE_VENDOR_SPEC(0x0763, 0x1033),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "M-Audio",
@@ -690,6 +725,22 @@
 		}
 	}
 },
+
+/* Mark of the Unicorn devices */
+{
+	/* thanks to Woodley Packard <sweaglesw@thibs.menloschool.org> */
+	USB_DEVICE(0x07fd, 0x0001),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "MOTU",
+		.product_name = "Fastlane",
+		.ifnum = 1,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0003,
+			.in_cables  = 0x0003
+		}
+	}
+},
 
 /*
  * Boot-up quirks
