2.6.7-rc1-mm1
--- diff/Documentation/BK-usage/bk-kernel-howto.txt	2004-05-27 13:41:08.000000000 +0100
+++ source/Documentation/BK-usage/bk-kernel-howto.txt	2004-05-27 18:34:14.000000000 +0100
@@ -279,5 +279,5 @@
    for my long-lived kernel branch?
 A. Yes.  This requires BK 3.x, though.
 
-	bk export -tpatch -r`bk repogca http://linux.bkbits.net/linux-2.5`,+
+	bk export -tpatch -r`bk repogca bk://linux.bkbits.net/linux-2.5`,+
 
--- diff/Documentation/BK-usage/gcapatch	2004-05-27 13:41:08.000000000 +0100
+++ source/Documentation/BK-usage/gcapatch	2004-05-27 18:34:14.000000000 +0100
@@ -5,4 +5,4 @@
 # Usage: gcapatch > foo.patch
 #
 
-bk export -tpatch -hdu -r`bk repogca http://linux.bkbits.net/linux-2.5`,+
+bk export -tpatch -hdu -r`bk repogca bk://linux.bkbits.net/linux-2.5`,+
--- diff/Documentation/binfmt_misc.txt	2004-05-19 22:10:50.000000000 +0100
+++ source/Documentation/binfmt_misc.txt	2004-05-27 18:34:14.000000000 +0100
@@ -15,7 +15,7 @@
 	mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc 
 
 To actually register a new binary type, you have to set up a string looking like
-:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon
+:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':' upon
 your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
 Here is what the fields mean:
  - 'name' is an identifier string. A new /proc file will be created with this
@@ -34,6 +34,28 @@
    The mask is anded with the byte sequence of the file.
  - 'interpreter' is the program that should be invoked with the binary as first
    argument (specify the full path)
+ - 'flags' is an optional field that controls several aspects of the invocation
+   of the interpreter. It is a string of capital letters, each controls a certain
+   aspect. The following flags are supported -
+      'P' - preserve-argv[0].  Legacy behavior of binfmt_misc is to overwrite the
+            original argv[0] with the full path to the binary.  When this flag is
+            included, binfmt_misc will add an argument to the argument vector for
+            this purpose, thus preserving the original argv[0].
+      'O' - open-binary. Legacy behavior of binfmt_misc is to pass the full path
+            of the binary to the interpreter as an argument. When this flag is
+            included, binfmt_misc will open the file for reading and pass its
+            descriptor as an argument, instead of the full path, thus allowing
+            the interpreter to execute non-readable binaries. This feature should
+            be used with care - the interpreter has to be trusted not to emit
+            the contents of the non-readable binary.
+      'C' - credentials. Currently, the behavior of binfmt_misc is to calculate
+            the credentials and security token of the new process according to
+            the interpreter. When this flag is included, these attributes are
+            calculated according to the binary. It also implies the 'O' flag.
+            This feature should be used with care as the interpreter
+            will run with root permissions when a setuid binary owned by root
+            is run with binfmt_misc.
+
 
 There are some restrictions:
  - the whole register string may not exceed 255 characters
@@ -83,9 +105,9 @@
 write a wrapper script for it. See Documentation/java.txt for an
 example.
 
-Your interpreter should NOT look in the PATH for the filename; the
-kernel passes it the full filename to use.  Using the PATH can cause
-unexpected behaviour and be a security hazard.
+Your interpreter should NOT look in the PATH for the filename; the kernel
+passes it the full filename (or the file descriptor) to use.  Using $PATH can
+cause unexpected behaviour and can be a security hazard.
 
 
 There is a web page about binfmt_misc at
--- diff/Documentation/filesystems/proc.txt	2004-05-27 13:41:09.000000000 +0100
+++ source/Documentation/filesystems/proc.txt	2004-05-27 18:34:14.000000000 +0100
@@ -201,7 +201,7 @@
  devices     Available devices (block and character)           
  dma         Used DMS channels                                 
  filesystems Supported filesystems                             
- driver	     Various drivers grouped here, currently rtc	(2.4)
+ driver	     Various drivers grouped here, currently rtc (2.4) and hpet (2.6)
  execdomains Execdomains, related to security			(2.4)
  fb	     Frame Buffer devices				(2.4)
  fs	     File system parameters, currently nfs/exports	(2.4)
--- diff/Documentation/kernel-parameters.txt	2004-05-19 22:10:50.000000000 +0100
+++ source/Documentation/kernel-parameters.txt	2004-05-27 18:34:14.000000000 +0100
@@ -896,8 +896,8 @@
 	psmouse.rate=	[HW,MOUSE] Set desired mouse report rate, in reports
 			per second.
 	psmouse.resetafter=
-			[HW,MOUSE] Try to reset Synaptics Touchpad after so many
-			bad packets (0 = never).
+			[HW,MOUSE] Try to reset the device after so many bad packets
+			(0 = never).
 	psmouse.resolution=
 			[HW,MOUSE] Set desired mouse resolution, in dpi.
 	psmouse.smartscroll=
--- diff/Documentation/laptop-mode.txt	2004-05-27 13:41:09.000000000 +0100
+++ source/Documentation/laptop-mode.txt	2004-05-27 18:34:14.000000000 +0100
@@ -279,7 +279,13 @@
 	fi
 }
 
-KLEVEL="$(uname -r | cut -c1-3)"
+KLEVEL=$(
+           uname -r |
+             (
+	       IFS="." read a b c
+	       echo $a.$b
+	     )
+	 )
 case "$KLEVEL" in
 	"2.4"|"2.6")
 		true
@@ -496,7 +502,7 @@
 
 case $status in
         "on-line")
-                echo "Setting HD spindown to 2 hours"
+                echo "Setting HD spindown for AC mode."
                 /sbin/laptop_mode stop
                 /sbin/hdparm -S $ACAD_HD /dev/hda > /dev/null 2>&1
                 /sbin/hdparm -B 255 /dev/hda > /dev/null 2>&1
@@ -504,7 +510,7 @@
                 exit 0
         ;;
         "off-line")
-                echo "Setting HD spindown to 20 seconds"
+                echo "Setting HD spindown for battery mode."
                 /sbin/laptop_mode start
                 /sbin/hdparm -S $BATT_HD /dev/hda > /dev/null 2>&1
                 /sbin/hdparm -B 1 /dev/hda > /dev/null 2>&1
--- diff/Documentation/networking/bridge.txt	2004-05-19 22:10:52.000000000 +0100
+++ source/Documentation/networking/bridge.txt	2004-05-27 18:34:14.000000000 +0100
@@ -1,11 +1,8 @@
-In order to use the ethernet bridging functionality you'll need the
-userspace tools available at http://www.math.leidenuniv.nl/~buytenh/bridge.
-The tarball available there contains extensive documentation, but if you
-still have questions, don't hesitate to post to the mailing list (more info
-at http://www.math.leidenuniv.nl/mailman/listinfo/bridge). You can also
-mail me at buytenh@gnu.org.
+In order to use the Ethernet bridging functionality, you'll need the
+userspace tools. These programs and documentation are available
+at http://bridge.sourceforge.net.  The download page is
+http://prdownloads.sourceforge.net/bridge.
 
+If you still have questions, don't hesitate to post to the mailing list 
+(more info http://lists.osdl.org/mailman/listinfo/bridge).
 
-
-Lennert Buytenhek
-<buytenh@gnu.org>
--- diff/Documentation/power/swsusp.txt	2004-05-27 13:41:09.000000000 +0100
+++ source/Documentation/power/swsusp.txt	2004-05-27 18:34:14.000000000 +0100
@@ -123,14 +123,15 @@
 replace ethernet card, resume. If you are fast your users will not
 even see broken connections.
 
-Q: Maybe I'm missing something, but why doesn't the regular io paths
-work?
 
-A: (Basically) you want to replace all kernel data with kernel data saved
-on disk. How do you do that using normal i/o paths? If you'll read
-"new" data 4KB at a time, you'll crash... because you still need "old"
-data to do the reading, and "new" data may fit on same physical spot
-in memory.
+Q: Maybe I'm missing something, but why don't the regular I/O paths work?
+
+A: We do use the regular I/O paths. However we cannot restore the data
+to its original location as we load it. That would create an
+inconsistent kernel state which would certainly result in an oops.
+Instead, we load the image into unused memory and then atomically copy
+it back to it original location. This implies, of course, a maximum
+image size of half the amount of memory.
 
 There are two solutions to this:
 
@@ -141,6 +142,10 @@
 between 0-640KB. That way, I'd have to make sure that 0-640KB is free
 during suspending, but otherwise it would work...
 
+suspend2 shares this fundamental limitation, but does not include user
+data and disk caches into "used memory" by saving them in
+advance. That means that the limitation goes away in practice.
+
 Q: Does linux support ACPI S4?
 
 A: No.
@@ -161,7 +166,7 @@
 
 Q: My machine doesn't work with ACPI. How can I use swsusp than ?
 
-A: Do reboot() syscall with right parameters. Warning: glibc gets in
+A: Do a reboot() syscall with right parameters. Warning: glibc gets in
 its way, so check with strace:
 
 reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 0xd000fce2)
@@ -181,3 +186,16 @@
             LINUX_REBOOT_CMD_SW_SUSPEND, 0);
     return 0;
 }
+
+Q: What is 'suspend2'?
+
+A: suspend2 is 'Software Suspend 2', a forked implementation of
+suspend-to-disk which is available as separate patches for 2.4 and 2.6
+kernels from swsusp.sourceforge.net. It includes support for SMP, 4GB
+highmem and preemption. It also has a extensible architecture that
+allows for arbitrary transformations on the image (compression,
+encryption) and arbitrary backends for writing the image (eg to swap
+or an NFS share[Work In Progress]). Questions regarding suspend2
+should be sent to the mailing list available through the suspend2
+website, and not to the Linux Kernel Mailing List. We are working
+toward merging suspend2 into the mainline kernel.
--- diff/Documentation/power/tricks.txt	2004-05-19 22:10:52.000000000 +0100
+++ source/Documentation/power/tricks.txt	2004-05-27 18:34:14.000000000 +0100
@@ -7,6 +7,8 @@
 * go with minimal config, turn off drivers like USB, AGP you don't
   really need
 
+* turn off APIC and preempt
+
 * use ext2. At least it has working fsck. [If something seemes to go
   wrong, force fsck when you have a chance]
 
--- diff/Documentation/power/video.txt	2004-05-19 22:10:52.000000000 +0100
+++ source/Documentation/power/video.txt	2004-05-27 18:34:14.000000000 +0100
@@ -30,6 +30,10 @@
   patched X, and plain text console (no vesafb or radeonfb), see
   http://www.doesi.gmxhome.de/linux/tm800s3/s3.html. (Acer TM 800)
 
+* radeon systems, where X can soft-boot your video card. You'll need
+  patched X, and plain text console (no vesafb or radeonfb), see
+  http://www.doesi.gmxhome.de/linux/tm800s3/s3.html. (Acer TM 800)
+
 Now, if you pass acpi_sleep=something, and it does not work with your
 bios, you'll get hard crash during resume. Be carefull.
 
--- diff/Documentation/sound/alsa/ALSA-Configuration.txt	2004-05-19 22:10:52.000000000 +0100
+++ source/Documentation/sound/alsa/ALSA-Configuration.txt	2004-05-27 18:34:14.000000000 +0100
@@ -416,7 +416,8 @@
 	* Creative Card w/Digital out + Digital I/O 2	[0x0fc3/0x1f0f]
 	* Creative Card w/Digital CD in + Digital I/O 2	[0x0fcf/0x1f0f]
         * Creative Card 5.1/w Digital out + LiveDrive	[0x3fc3/0x1fff]
-        * Creative Card all ins and outs		[0x3fff/0x1fff]
+	* Creative Card 5.1 (c) 2003			[0x3fc3/0x7cff]
+        * Creative Card all ins and outs		[0x3fff/0x7fff]
     
   Module snd-ens1370
   ------------------
@@ -609,6 +610,10 @@
                         * Hoontech SoundTrack DSP 24 Media 7.1
                         * Digigram VX442
 
+    model       - Use the given board model, one of the following:
+		  delta1010, dio2496, delta66, delta44, audiophile, delta410,
+		  delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d,
+		  dmx6fire, dsp24, dsp24_71, ez8
     omni	- Omni I/O support for MidiMan M-Audio Delta44/66
     cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever)
                      in msec resolution, default value is 500 (0.5 sec)
@@ -625,6 +630,9 @@
 			* AMP Ltd AUDIO2000
 			* TerraTec Aureon Sky-5.1, Space-7.1
 
+    model       - Use the given board model, one of the following:
+		  revo71, amp2000, prodigy71, aureon51, aureon71
+
     Module supports up to 8 cards and autoprobe.
 
   Module snd-intel8x0
@@ -787,6 +795,8 @@
 
     Module supports autoprobe and multiple chips (max 8).
 
+    The power-management is supported.
+
     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 explicity via
@@ -796,9 +806,24 @@
       Sony F270: buffer_top=0x272800
     The driver supports only ac97 codec.  It's possible to force
     to initialize/use ac97 although it's not detected.  In such a
-    case, use force_ac97=1 option.
+    case, use force_ac97=1 option - but *NO* guarantee whether it
+    works!
 
-    The power-management is supported.
+    Note: The NM256 chip can be linked internally with non-AC97
+    codecs.  This driver supports only the AC97 codec, and won't work
+    with machines with other (most likely CS423x or OPL3SAx) chips,
+    even though the device is detected in lspci.  In such a case, try
+    other drivers, e.g. snd-cs4232 or snd-opl3sa2.  Some has ISA-PnP
+    but some doesn't have ISA PnP.  You'll need to speicfy isapnp=0
+    and proper hardware parameters in the case without ISA PnP.
+
+    Note: This driver is really crappy.  It's a porting from the
+    OSS driver, which is a result of black-magic reverse engineering.
+    The detection of codec will fail if the driver is loaded *after*
+    X-server as described above.  You might be able to force to load
+    the module, but it may result in hang-up.   Hence, make sure that
+    you load this module *before* X if you encounter this kind of
+    problem.
 
   Module snd-opl3sa2
   ------------------
--- diff/Documentation/sound/alsa/CMIPCI.txt	2004-05-19 22:10:52.000000000 +0100
+++ source/Documentation/sound/alsa/CMIPCI.txt	2004-05-27 18:34:14.000000000 +0100
@@ -180,8 +180,8 @@
 device automatically to the previous state.
 
 On the model 033, AC3 is implemented by the software conversion in
-the driver.  This prevents the mmap support.  If you need mmap
-support, pass the "soft_ac3=0" module option.  This doesn't matter
+the alsa-lib.  If you need to bypass the software conversion of IEC958
+subframes, pass the "soft_ac3=0" module option.  This doesn't matter
 on the newer models.
 
 
--- diff/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	2004-05-19 22:10:52.000000000 +0100
+++ source/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	2004-05-27 18:34:14.000000000 +0100
@@ -511,7 +511,7 @@
           }
 
           // (7)
-          pci_set_drvdata(pci, chip);
+          pci_set_drvdata(pci, card);
           dev++;
           return 0;
   }
@@ -519,10 +519,7 @@
   // destructor -- see "Destructor" sub-section
   static void __devexit snd_mychip_remove(struct pci_dev *pci)
   {
-          mychip_t *chip = snd_magic_cast(mychip_t,
-                                     pci_get_drvdata(pci), return);
-          if (chip)
-                  snd_card_free(chip->card);
+          snd_card_free(pci_get_drvdata(pci));
           pci_set_drvdata(pci, NULL);
   }
 ]]>
@@ -691,21 +688,16 @@
           <informalexample>
             <programlisting>
 <![CDATA[
-        pci_set_drvdata(pci, chip);
+        pci_set_drvdata(pci, card);
         dev++;
         return 0;
 ]]>
             </programlisting>
           </informalexample>
 
-          In the above, the chip record is stored. This pointer is
+          In the above, the card record is stored. This pointer is
         referred in the remove callback and power-management
         callbacks, too. 
-	If the card doesn't support the suspend/resume, you can store
-        the card pointer instead of the chip pointer, so that
-        <function>snd_card_free</function> can be called directly
-        without cast in the remove callback.  But anyway, be sure
-        which pointer is used.
         </para>
       </section>
     </section>
@@ -726,21 +718,15 @@
 <![CDATA[
   static void __devexit snd_mychip_remove(struct pci_dev *pci)
   {
-          mychip_t *chip = snd_magic_cast(mychip_t,
-                                    pci_get_drvdata(pci), return);
-          if (chip)
-                  snd_card_free(chip->card);
+          snd_card_free(pci_get_drvdata(pci));
           pci_set_drvdata(pci, NULL);
   }
 ]]>
           </programlisting>
         </informalexample>
 
-        The above code assumes that the chip is allocated
-	with snd_magic stuff and
-      has the field to hold the card pointer (see <link
-      linkend="card-management"><citetitle>the next
-      section</citetitle></link>). 
+        The above code assumes that the card pointer is set to the PCI
+	driver data.
       </para>
     </section>
 
@@ -1355,16 +1341,7 @@
   // initialization of the module
   static int __init alsa_card_mychip_init(void)
   {
-          int err;
-
-          if ((err = pci_module_init(&driver)) < 0) {
-  #ifdef MODULE
-                  printk(KERN_ERR "My chip soundcard not found "
-                                  "or device busy\n");
-  #endif
-                  return err;
-          }
-          return 0;
+          return pci_module_init(&driver);
   }
 
   // clean up the module
@@ -1781,16 +1758,7 @@
 <![CDATA[
   static int __init alsa_card_mychip_init(void)
   {
-          int err;
-
-          if ((err = pci_module_init(&driver)) < 0) {
-  #ifdef MODULE
-                  printk(KERN_ERR "My chip soundcard not found"
-                                  " or device busy\n");
-  #endif
-                  return err;
-          }
-          return 0;
+          return pci_module_init(&driver);
   }
 
   static void __exit alsa_card_mychip_exit(void)
@@ -5254,47 +5222,23 @@
     </para>
 
     <para>
-      Basic jobs of suspend/resume are done in
-      <structfield>suspend</structfield> and
-      <structfield>resume</structfield> callbacks of
-      <structname>pci_driver</structname> struct. Unfortunately, the
-      API of these callbacks was changed at the middle time of Linux
-      2.4.x, if you want to keep the support for older kernels, you
-      have to write two different callbacks. The example below is the
-      skeleton callbacks which just call the real suspend and resume
-      functions. 
+      ALSA provides the common power-management layer. Each card driver
+      needs to have only low-level suspend and resume callbacks.
 
       <informalexample>
         <programlisting>
 <![CDATA[
-  #ifndef PCI_OLD_SUSPEND
-  static int snd_my_suspend(struct pci_dev *dev, u32 state)
+  #ifdef CONFIG_PM
+  static int snd_my_suspend(snd_card_t *card, unsigned int state)
   {
-          mychip_t *chip = snd_magic_cast(mychip_t,
-                             pci_get_drvdata(dev), return -ENXIO);
-          mychip_suspend(chip);
+          .... // do things for suspsend
           return 0;
   }
-  static int snd_my_resume(struct pci_dev *dev)
+  static int snd_my_resume(snd_card_t *card, unsigned int state)
   {
-          mychip_t *chip = snd_magic_cast(mychip_t,
-                             pci_get_drvdata(dev), return -ENXIO);
-          mychip_resume(chip);
+          .... // do things for suspsend
           return 0;
   }
-  #else
-  static void snd_my_suspend(struct pci_dev *dev)
-  {
-          mychip_t *chip = snd_magic_cast(mychip_t,
-                             pci_get_drvdata(dev), return);
-          mychip_suspend(chip);
-  }
-  static void snd_mychip_resume(struct pci_dev *dev)
-  {
-          mychip_t *chip = snd_magic_cast(mychip_t,
-                             pci_get_drvdata(dev), return);
-          mychip_resume(chip);
-  }
   #endif
 ]]>
         </programlisting>
@@ -5302,17 +5246,10 @@
     </para>
 
     <para>
-      For keeping the readability of 2.6 source code, it's recommended to
-      separate the above ifdef condition as the patch file in alsa-driver
-      directory.
-      See <filename>alsa-driver/pci/ali5451.c</filename> for example.
-   </para>
-
-    <para>
       The scheme of the real suspend job is as following.
 
       <orderedlist>
-        <listitem><para>Check whether the power-state is already D3hot. If yes, skip the job.</para></listitem>
+        <listitem><para>Retrieve the chip data from pm_private_data field.</para></listitem>
         <listitem><para>Call <function>snd_pcm_suspend_all()</function> to suspend the running PCM streams.</para></listitem>
         <listitem><para>Save the register values if necessary.</para></listitem>
         <listitem><para>Stop the hardware if necessary.</para></listitem>
@@ -5326,12 +5263,11 @@
       <informalexample>
         <programlisting>
 <![CDATA[
-  static void mychip_suspend(mychip_t *chip)
+  static int mychip_suspend(snd_card_t *card, unsigned int state)
   {
-          snd_card_t *card = chip->card;
           // (1)
-          if (card->power_state == SNDRV_CTL_POWER_D3hot)
-                  return;
+          mychip_t *chip = snd_magic_cast(mychip_t, card->pm_private_data,
+                                          return -ENXIO);
           // (2)
           snd_pcm_suspend_all(chip->pcm);
           // (3)
@@ -5340,6 +5276,7 @@
           snd_mychip_stop_hardware(chip);
           // (5)
           snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+          return 0;
   }
 ]]>
         </programlisting>
@@ -5350,8 +5287,7 @@
     The scheme of the real resume job is as following.
 
     <orderedlist>
-    <listitem><para>Check whether the power-state is already D0.
-    If yes, skip the job.</para></listitem>
+    <listitem><para>Retrieve the chip data from pm_private_data field.</para></listitem>
     <listitem><para>Enable the pci device again by calling
     <function>pci_enable_device()</function>.</para></listitem>
     <listitem><para>Re-initialize the chip.</para></listitem>
@@ -5372,10 +5308,9 @@
 <![CDATA[
   static void mychip_resume(mychip_t *chip)
   {
-          snd_card_t *card = chip->card;
           // (1)
-          if (card->power_state == SNDRV_CTL_POWER_D0)
-                  return;
+          mychip_t *chip = snd_magic_cast(mychip_t, card->pm_private_data,
+                                          return -ENXIO);
           // (2)
           pci_enable_device(chip->pci);
           // (3)
@@ -5388,38 +5323,6 @@
           snd_mychip_restart_chip(chip);
           // (7)
           snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-  }
-]]>
-        </programlisting>
-      </informalexample>
-    </para>
-
-    <para>
-      In addition to the callbacks above, you should define a callback
-      for the changes via the ALSA control interface. It's defined
-      like below: 
-
-      <informalexample>
-        <programlisting>
-<![CDATA[
-  static int snd_mychip_set_power_state(snd_card_t *card,
-                                        unsigned int power_state)
-  {
-          mychip_t *chip = snd_magic_cast(mychip_t,
-                   card->power_state_private_data, return -ENXIO);
-          switch (power_state) {
-          case SNDRV_CTL_POWER_D0:
-          case SNDRV_CTL_POWER_D1:
-          case SNDRV_CTL_POWER_D2:
-                  mychip_resume(chip);
-                  break;
-          case SNDRV_CTL_POWER_D3hot:
-          case SNDRV_CTL_POWER_D3cold:
-                  mychip_suspend(chip);
-                  break;
-          default:
-                  return -EINVAL;
-          }
           return 0;
   }
 ]]>
@@ -5439,41 +5342,42 @@
   {
           ....
           snd_card_t *card;
+          mychip_t *chip;
           ....
-  #ifdef CONFIG_PM
-          card->set_power_state = snd_mychip_set_power_state;
-          card->power_state_private_data = chip;
-  #endif
+          snd_card_set_pm_callback(card, snd_my_suspend, snd_my_resume, chip);
           ....
   }
 ]]>
         </programlisting>
       </informalexample>
+
+    Here you don't have to put ifdef CONFIG_PM around, since it's already
+    checked in the header and expanded to empty if not needed.
     </para>
 
     <para>
       If you need a space for saving the registers, you'll need to
-    allocate the buffer for it here, too, since you cannot call
-    <function>kmalloc()</function> with
-    <constant>GFP_KERNEL</constant> flag or
-    <function>vmalloc()</function> in the suspend callback.
+    allocate the buffer for it here, too, since it would be fatal
+    if you cannot allocate a memory in the suspend phase.
     The allocated buffer should be released in the corresponding
     destructor.
     </para>
 
     <para>
       And next, set suspend/resume callbacks to the pci_driver,
+      This can be done by passing a macro SND_PCI_PM_CALLBACKS
+      in the pci_driver struct.  This macro is expanded to the correct
+      (global) callbacks if CONFIG_PM is set.
 
       <informalexample>
         <programlisting>
 <![CDATA[
   static struct pci_driver driver = {
           .name = "My Chip",
-          ....
-  #ifdef CONFIG_PM
-          .suspend = snd_mychip_suspend,
-          .resume = snd_mychip_resume,
-  #endif
+          .id_table = snd_my_ids,
+          .probe = snd_my_probe,
+          .remove = __devexit_p(snd_my_remove),
+          SND_PCI_PM_CALLBACKS
   };
 ]]>
         </programlisting>
@@ -5521,7 +5425,8 @@
 
     <para>
       The module parameters must be declared with the standard
-    <function>MODULE_PARM()</function> and
+    <function>module_param()()</function>,
+    <function>module_param_array()()</function> and
     <function>MODULE_PARM_DESC()</function> macros. The ALSA provides
     an additional macro, <function>MODULE_PARM_SYNTAX()</function>,
     for describing its syntax. The strings will be written to
@@ -5545,18 +5450,22 @@
 <![CDATA[
   #define CARD_NAME "My Chip"
 
-  MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+  static int boot_devs;
+  module_param_array(index, int, boot_devs, 0444);
   MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
   MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-  MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+  module_param_array(id, charp, boot_devs, 0444);
   MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
   MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-  MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+  module_param_array(enable, bool, boot_devs, 0444);
   MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
   MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 ]]>
         </programlisting>
       </informalexample>
+
+    Here boot_devs is passed but simply ignored since we don't care
+    the number of parsed parameters.
     </para>
 
     <para>
@@ -5577,39 +5486,6 @@
       </informalexample>
     </para>
 
-    <para>
-      For building the driver into kernel, you should define the
-      <function>setup()</function> function in addition, too. 
-      ALSA provides <function>get_id()</function> function to retrieve
-      a string argument from the kernel boot parameters.
-
-      <informalexample>
-        <programlisting>
-<![CDATA[
-  #ifndef MODULE
-
-  /* format is: snd-mychip=enable,index,id */
-
-  static int __init alsa_card_mychip_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-mychip=", alsa_card_mychip_setup);
-
-  #endif /* ifndef MODULE */
-]]>
-        </programlisting>
-      </informalexample>
-    </para>
   </chapter>
 
 
@@ -5631,10 +5507,14 @@
 	Suppose that you'll create a new PCI driver for the card
 	<quote>xyz</quote>.  The card module name would be
 	snd-xyz.  The new driver is usually put into alsa-driver
-	tree.  Then the driver is evaluated, audited and tested
+	tree, <filename>alsa-driver/pci</filename> directory in
+	the case of PCI cards.
+	Then the driver is evaluated, audited and tested
 	by developers and users.  After a certain time, the driver
-	will go to alsa-kernel tree and eventually integrated into
-	Linux 2.6 tree.
+	will go to alsa-kernel tree (to the corresponding directory,
+	such as <filename>alsa-kernel/pci</filename>) and eventually
+	integrated into Linux 2.6 tree (the directory would be
+	<filename>linux/sound/pci</filename>).
 	</para>
 
 	<para>
@@ -5661,7 +5541,7 @@
         <programlisting>
 <![CDATA[
   snd-xyz-objs := xyz.o
-  extra-obj-$(CONFIG_SND_XYZ) += snd-xyz.o
+  obj-$(CONFIG_SND_XYZ) += snd-xyz.o
 ]]>
         </programlisting>
       </informalexample>
@@ -5678,8 +5558,8 @@
       <informalexample>
         <programlisting>
 <![CDATA[
-  config SND_BT87X
-          tristate "Foobar XYX"
+  config SND_XYZ
+          tristate "Foobar XYZ"
           depends on SND
           select SND_PCM
           help
@@ -5730,7 +5610,8 @@
 	<orderedlist>
 	<listitem>
 	<para>
-	Add a new directory (xyz) to extra-subdir-y list in alsa-driver/pci/Makefile
+	Add a new directory (<filename>xyz</filename>) in
+	<filename>alsa-driver/pci/Makefile</filename> like below
 
       <informalexample>
         <programlisting>
@@ -5744,7 +5625,7 @@
 
 	<listitem>
 	<para>
-	Under the directory xyz, create a Makefile
+	Under the directory <filename>xyz</filename>, create a Makefile
 
       <example>
 	<title>Sample Makefile for a driver xyz</title>
--- diff/Documentation/sound/alsa/Procfile.txt	2004-05-19 22:10:52.000000000 +0100
+++ source/Documentation/sound/alsa/Procfile.txt	2004-05-27 18:34:14.000000000 +0100
@@ -131,6 +131,12 @@
 card*/codec97#0/ac97#?-?+regs
 	Shows the AC97 register dump.  Useful for debugging.
 
+	When CONFIG_SND_DEBUG is enabled, you can write to this file for
+	changing an AC97 register directly.  Pass two hex numbers.
+	For example,
+
+	# echo 02 9f1f > /proc/asound/card0/codec97#0/ac97#0-0+regs
+
 
 Sequencer Information
 ---------------------
--- diff/MAINTAINERS	2004-05-27 13:41:09.000000000 +0100
+++ source/MAINTAINERS	2004-05-27 18:34:14.000000000 +0100
@@ -90,6 +90,20 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+3W-XXXX ATA-RAID CONTROLLER DRIVER
+P:	Adam Radford
+M:	linuxraid@amcc.com
+L:	linux-scsi@vger.kernel.org
+W:	http://www.amcc.com
+S:	Supported
+
+3W-9XXX SATA-RAID CONTROLLER DRIVER
+P:	Adam Radford
+M:	linuxraid@amcc.com
+L:	linux-scsi@vger.kernel.org
+W:	http://www.amcc.com
+S:	Supported
+
 53C700 AND 53C700-66 SCSI DRIVER
 P:	James E.J. Bottomley
 M:	James.Bottomley@HansenPartnership.com
@@ -538,11 +552,6 @@
 W:     http://sourceforge.net/projects/cramfs/
 S:     Orphan
 
-CREDITS FILE
-P:	John A. Martin
-M:	jam@acm.org
-S:	Maintained
-
 CRIS PORT
 P:	Bjorn Wesen
 M:	bjornw@axis.com
@@ -1204,6 +1213,12 @@
 W:	http://developer.osdl.org/rddunlap/kj-patches/
 S:	Maintained
 
+KGDB FOR I386 PLATFORM
+P:	George Anzinger
+M:	george@mvista.com
+L:	linux-net@vger.kernel.org
+S:	Supported
+
 KERNEL NFSD
 P:	Neil Brown
 M:	neilb@cse.unsw.edu.au
--- diff/Makefile	2004-05-27 13:41:09.000000000 +0100
+++ source/Makefile	2004-05-27 18:34:14.000000000 +0100
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 7
-EXTRAVERSION =-rc1
+EXTRAVERSION =-rc1-mm1
 NAME=Zonked Quokka
 
 # *DOCUMENTATION*
@@ -461,6 +461,7 @@
 
 ifdef CONFIG_DEBUG_INFO
 CFLAGS		+= -g
+AFLAGS		+= -g
 endif
 
 # warn about C99 declaration after statement
@@ -680,7 +681,7 @@
 uts_len := 64
 
 define filechk_version.h
-	if ((`echo -n "$(KERNELRELEASE)" | wc -c ` > $(uts_len))); then \
+	if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
 	  echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \
 	  exit 1; \
 	fi; \
@@ -1065,6 +1066,11 @@
 endif #ifeq ($(config-targets),1)
 endif #ifeq ($(mixed-targets),1)
 
+.PHONY: checkstack
+checkstack:
+	$(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
+	$(PERL) scripts/checkstack.pl $(ARCH)
+
 # FIXME Should go into a make.lib or something 
 # ===========================================================================
 
--- diff/arch/alpha/kernel/init_task.c	2004-05-19 22:10:53.000000000 +0100
+++ source/arch/alpha/kernel/init_task.c	2004-05-27 18:34:14.000000000 +0100
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 #include <asm/uaccess.h>
 
 
--- diff/arch/alpha/kernel/setup.c	2004-05-19 22:10:53.000000000 +0100
+++ source/arch/alpha/kernel/setup.c	2004-05-27 18:34:14.000000000 +0100
@@ -122,7 +122,6 @@
 static void determine_cpu_caches (unsigned int);
 
 static char command_line[COMMAND_LINE_SIZE];
-char saved_command_line[COMMAND_LINE_SIZE];
 
 /*
  * The format of "screen_info" is strange, and due to early
--- diff/arch/arm/Kconfig	2004-05-27 13:41:09.000000000 +0100
+++ source/arch/arm/Kconfig	2004-05-27 18:34:14.000000000 +0100
@@ -84,9 +84,6 @@
 config ARCH_CO285
 	bool "Co-EBSA285"
 
-config ARCH_PXA
-	bool "PXA2xx-based"
-
 config ARCH_EBSA110
 	bool "EBSA-110"
 	help
@@ -126,6 +123,9 @@
 	  If you have any questions or comments about the Linux kernel port
 	  to this board, send e-mail to sjhill@cotw.com.
 
+config ARCH_PXA
+	bool "PXA2xx-based"
+
 config ARCH_RPC
 	bool "RiscPC"
 	help
@@ -135,9 +135,6 @@
 config ARCH_SA1100
 	bool "SA1100-based"
 
-config ARCH_SHARK
-	bool "Shark"
-
 config ARCH_S3C2410
 	bool "Samsung S3C2410"
 	help
@@ -145,8 +142,8 @@
 	  BAST (http://www.simtec.co.uk/products/EB110ITX/), the IPAQ 1940 or
 	  the Samsung SMDK2410 development board (and derviatives).
 
-config ARCH_OMAP
-	bool "TI OMAP"
+config ARCH_SHARK
+	bool "Shark"
 
 config ARCH_LH7A40X
 	bool "Sharp LH7A40X"
@@ -156,6 +153,9 @@
 	  core with a wide array of integrated devices for
 	  hand-held and low-power applications.
 
+config ARCH_OMAP
+	bool "TI OMAP"
+
 config ARCH_VERSATILE_PB
 	bool "Versatile PB"
 	help
--- diff/arch/arm/common/dmabounce.c	2004-05-27 13:41:10.000000000 +0100
+++ source/arch/arm/common/dmabounce.c	2004-05-27 18:34:14.000000000 +0100
@@ -100,6 +100,7 @@
 		if (d->dev == dev)
 			return d;
 	}
+	return NULL;
 }
 
 
--- diff/arch/arm/kernel/arch.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/kernel/arch.c	2004-05-27 18:34:14.000000000 +0100
@@ -10,7 +10,6 @@
 #include <asm/elf.h>
 #include <asm/page.h>
 #include <asm/setup.h>
-#include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
 unsigned int vram_size;
--- diff/arch/arm/kernel/init_task.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/kernel/init_task.c	2004-05-27 18:34:14.000000000 +0100
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/arm/kernel/setup.c	2004-05-27 13:41:10.000000000 +0100
+++ source/arch/arm/kernel/setup.c	2004-05-27 18:34:14.000000000 +0100
@@ -95,7 +95,6 @@
 char elf_platform[ELF_PLATFORM_SIZE];
 EXPORT_SYMBOL(elf_platform);
 
-char saved_command_line[COMMAND_LINE_SIZE];
 unsigned long phys_initrd_start __initdata = 0;
 unsigned long phys_initrd_size __initdata = 0;
 
--- diff/arch/arm/mach-adifcc/irq.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-adifcc/irq.c	2004-05-27 18:34:14.000000000 +0100
@@ -19,8 +19,6 @@
 #include <asm/irq.h>
 #include <asm/hardware.h>
 
-#include <asm/mach-types.h>
-
 static void xs80200_irq_mask (unsigned int irq)
 {
 	long INTCTL;
--- diff/arch/arm/mach-iop3xx/iop310-irq.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-iop3xx/iop310-irq.c	2004-05-27 18:34:14.000000000 +0100
@@ -21,8 +21,6 @@
 #include <asm/irq.h>
 #include <asm/hardware.h>
 
-#include <asm/mach-types.h>
-
 extern void xs80200_irq_mask(unsigned int);
 extern void xs80200_irq_unmask(unsigned int);
 extern void xs80200_init_irq(void);
--- diff/arch/arm/mach-iop3xx/iop321-time.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-iop3xx/iop321-time.c	2004-05-27 18:34:14.000000000 +0100
@@ -23,7 +23,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
-#include <asm/mach-types.h>
 #include <asm/mach/irq.h>
 
 static unsigned long iop321_gettimeoffset(void)
--- diff/arch/arm/mach-iop3xx/iq80310-irq.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-iop3xx/iq80310-irq.c	2004-05-27 18:34:14.000000000 +0100
@@ -22,8 +22,6 @@
 #include <asm/hardware.h>
 #include <asm/system.h>
 
-#include <asm/mach-types.h>
-
 extern void iop310_init_irq(void);
 extern void iop310_irq_demux(unsigned int, struct irqdesc *, struct pt_regs *);
 
--- diff/arch/arm/mach-iop3xx/iq80310-time.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-iop3xx/iq80310-time.c	2004-05-27 18:34:14.000000000 +0100
@@ -21,7 +21,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
-#include <asm/mach-types.h>
 #include <asm/mach/irq.h>
 
 static void iq80310_write_timer (u_long val)
--- diff/arch/arm/mach-iop3xx/mm-321.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-iop3xx/mm-321.c	2004-05-27 18:34:14.000000000 +0100
@@ -21,7 +21,6 @@
 #include <asm/page.h>
 
 #include <asm/mach/map.h>
-#include <asm/mach-types.h>
 
 
 /*
--- diff/arch/arm/mach-iop3xx/mm.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-iop3xx/mm.c	2004-05-27 18:34:14.000000000 +0100
@@ -23,7 +23,6 @@
 #include <asm/page.h>
 
 #include <asm/mach/map.h>
-#include <asm/mach-types.h>
 
 #ifdef CONFIG_IOP310_MU
 #include "message.h"
--- diff/arch/arm/mach-iop3xx/xs80200-irq.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-iop3xx/xs80200-irq.c	2004-05-27 18:34:14.000000000 +0100
@@ -17,8 +17,6 @@
 #include <asm/irq.h>
 #include <asm/hardware.h>
 
-#include <asm/mach-types.h>
-
 static void xs80200_irq_mask (unsigned int irq)
 {
 	unsigned long intctl;
--- diff/arch/arm/mach-ixp4xx/common.c	2004-05-27 13:41:10.000000000 +0100
+++ source/arch/arm/mach-ixp4xx/common.c	2004-05-27 18:34:14.000000000 +0100
@@ -30,7 +30,6 @@
 #include <asm/hardware.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/mach-types.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
--- diff/arch/arm/mach-omap/bus.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/mach-omap/bus.c	2004-05-27 18:34:14.000000000 +0100
@@ -39,7 +39,6 @@
 #include <linux/spinlock.h>
 
 #include <asm/hardware.h>
-#include <asm/mach-types.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
--- diff/arch/arm/mach-pxa/generic.c	2004-05-27 13:41:10.000000000 +0100
+++ source/arch/arm/mach-pxa/generic.c	2004-05-27 18:34:14.000000000 +0100
@@ -104,6 +104,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &pxamci_dmamask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(pxamci_resources),
 	.resource	= pxamci_resources,
--- diff/arch/arm/mach-pxa/lubbock.c	2004-05-19 22:10:56.000000000 +0100
+++ source/arch/arm/mach-pxa/lubbock.c	2004-05-27 18:34:14.000000000 +0100
@@ -11,11 +11,12 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/major.h>
-#include <linux/fs.h>
+#include <linux/fb.h>
 #include <linux/interrupt.h>
 
 #include <asm/setup.h>
@@ -29,11 +30,22 @@
 #include <asm/mach/irq.h>
 
 #include <asm/arch/udc.h>
+#include <asm/arch/pxafb.h>
 #include <asm/hardware/sa1111.h>
 
 #include "generic.h"
 
 
+void lubbock_set_misc_wr(unsigned int mask, unsigned int set)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	LUB_MISC_WR = (LUB_MISC_WR & ~mask) | (set & mask);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(lubbock_set_misc_wr);
+
 static unsigned long lubbock_irq_enabled;
 
 static void lubbock_mask_irq(unsigned int irq)
@@ -148,9 +160,29 @@
 	&smc91x_device,
 };
 
+static struct pxafb_mach_info sharp_lm8v31 __initdata = {
+	.pixclock	= 270000,
+	.xres		= 640,
+	.yres		= 480,
+	.bpp		= 16,
+	.hsync_len	= 1,
+	.left_margin	= 3,
+	.right_margin	= 3,
+	.vsync_len	= 1,
+	.upper_margin	= 0,
+	.lower_margin	= 0,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.cmap_greyscale	= 0,
+	.cmap_inverse	= 0,
+	.cmap_static	= 0,
+	.lccr0		= LCCR0_SDS,
+	.lccr3		= LCCR3_PCP | LCCR3_Acb(255),
+};
+
 static void __init lubbock_init(void)
 {
 	pxa_set_udc_info(&udc_info);
+	set_pxa_fb_info(&sharp_lm8v31);
 	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
--- diff/arch/arm/mach-s3c2410/s3c2410.c	2004-05-19 22:10:56.000000000 +0100
+++ source/arch/arm/mach-s3c2410/s3c2410.c	2004-05-27 18:34:14.000000000 +0100
@@ -31,7 +31,6 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/mach-types.h>
 
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/regs-serial.h>
--- diff/arch/arm26/kernel/init_task.c	2004-05-19 22:10:58.000000000 +0100
+++ source/arch/arm26/kernel/init_task.c	2004-05-27 18:34:14.000000000 +0100
@@ -10,6 +10,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/arm26/kernel/setup.c	2004-05-19 22:10:58.000000000 +0100
+++ source/arch/arm26/kernel/setup.c	2004-05-27 18:34:14.000000000 +0100
@@ -76,7 +76,6 @@
 
 unsigned char aux_device_present;
 char elf_platform[ELF_PLATFORM_SIZE];
-char saved_command_line[COMMAND_LINE_SIZE];
 
 unsigned long phys_initrd_start __initdata = 0;
 unsigned long phys_initrd_size __initdata = 0;
--- diff/arch/cris/kernel/process.c	2004-05-19 22:10:59.000000000 +0100
+++ source/arch/cris/kernel/process.c	2004-05-27 18:34:14.000000000 +0100
@@ -102,6 +102,7 @@
 #include <linux/fs.h>
 #include <linux/user.h>
 #include <linux/elfcore.h>
+#include <linux/mqueue.h>
 
 //#define DEBUG
 
--- diff/arch/cris/kernel/setup.c	2004-05-19 22:10:59.000000000 +0100
+++ source/arch/cris/kernel/setup.c	2004-05-27 18:34:14.000000000 +0100
@@ -28,10 +28,7 @@
 extern int root_mountflags;
 extern char _etext, _edata, _end;
 
-#define COMMAND_LINE_SIZE 256
-
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
 
 extern const unsigned long text_start, edata; /* set by the linker script */
 extern unsigned long dram_start, dram_end;
--- diff/arch/h8300/kernel/h8300_ksyms.c	2004-05-27 13:41:10.000000000 +0100
+++ source/arch/h8300/kernel/h8300_ksyms.c	2004-05-27 18:34:14.000000000 +0100
@@ -40,6 +40,8 @@
 EXPORT_SYMBOL(ip_fast_csum);
 
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
--- diff/arch/h8300/kernel/init_task.c	2004-05-19 22:10:59.000000000 +0100
+++ source/arch/h8300/kernel/init_task.c	2004-05-27 18:34:14.000000000 +0100
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/h8300/kernel/module.c	2004-05-27 13:41:10.000000000 +0100
+++ source/arch/h8300/kernel/module.c	2004-05-27 18:34:14.000000000 +0100
@@ -67,7 +67,6 @@
 		Elf32_Sym *sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
 			+ ELF32_R_SYM(rela[i].r_info);
 		uint32_t v = sym->st_value + rela[i].r_addend;
-		uint32_t dot = sechdrs[symindex].sh_addr + rela[i].r_offset;
 
 		switch (ELF32_R_TYPE(rela[i].r_info)) {
 		case R_H8_DIR24R8:
@@ -75,14 +74,15 @@
 			*loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v);
 			break;
 		case R_H8_DIR24A8:
-			*loc += v;
+			if (ELF32_R_SYM(rela[i].r_info))
+				*loc += v;
 			break;
 		case R_H8_DIR32:
 		case R_H8_DIR32A16:
 			*loc += v;
 			break;
 		case R_H8_PCREL16:
-			v -= dot + 2;
+			v -= (unsigned long)loc + 2;
 			if ((Elf32_Sword)v > 0x7fff || 
 			    (Elf32_Sword)v < -(Elf32_Sword)0x8000)
 				goto overflow;
@@ -90,7 +90,7 @@
 				*(unsigned short *)loc = v;
 			break;
 		case R_H8_PCREL8:
-			v -= dot + 1;
+			v -= (unsigned long)loc + 1;
 			if ((Elf32_Sword)v > 0x7f || 
 			    (Elf32_Sword)v < -(Elf32_Sword)0x80)
 				goto overflow;
@@ -105,7 +105,7 @@
 	}
 	return 0;
  overflow:
-	printk(KERN_ERR "module %s: relocation offset overflow: %p\n",
+	printk(KERN_ERR "module %s: relocation offset overflow: %08x\n",
 	       me->name, rela[i].r_offset);
 	return -ENOEXEC;
 }
--- diff/arch/h8300/kernel/setup.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/h8300/kernel/setup.c	2004-05-27 18:34:14.000000000 +0100
@@ -30,6 +30,7 @@
 #include <linux/major.h>
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -54,8 +55,7 @@
 unsigned long memory_start;
 unsigned long memory_end;
 
-char command_line[512];
-char saved_command_line[512];
+char command_line[COMMAND_LINE_SIZE];
 
 extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
 extern int _ramstart, _ramend;
--- diff/arch/i386/Kconfig	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/Kconfig	2004-05-27 18:34:14.000000000 +0100
@@ -434,7 +434,8 @@
 	  Choose N to continue using the legacy 8254 timer.
 
 config HPET_EMULATE_RTC
-	def_bool HPET_TIMER && RTC=y
+	bool "Provide RTC interrupt"
+	depends on HPET_TIMER && RTC=y
 
 config SMP
 	bool "Symmetric multi-processing support"
@@ -849,17 +850,7 @@
 	default y
 
 config REGPARM
-	bool "Use register arguments (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
-	default n
-	help
-	Compile the kernel with -mregparm=3. This uses an different ABI
-	and passes the first three arguments of a function call in registers.
-	This will probably break binary only modules.
-
-	This feature is only enabled for gcc-3.0 and later - earlier compilers
-	generate incorrect output with certain kernel constructs when
-	-mregparm=3 is used.
+	def_bool y
 
 endmenu
 
@@ -1255,6 +1246,15 @@
 	  This results in a large slowdown, but helps to find certain types
 	  of memory corruptions.
 
+config SPINLINE
+	bool "Spinlock inlining"
+	depends on DEBUG_KERNEL
+	help
+	  This will change spinlocks from out of line to inline, making them
+	  account cost to the callers in readprofile, rather than the lock
+	  itself (as ".text.lock.filename"). This can be helpful for finding
+	  the callers of locks.
+
 config DEBUG_HIGHMEM
 	bool "Highmem debugging"
 	depends on DEBUG_KERNEL && HIGHMEM
@@ -1271,12 +1271,194 @@
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
 	  
+config LOCKMETER
+	bool "Kernel lock metering"
+	depends on SMP
+	help
+	  Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+	  but allows you to see various statistics using the lockstat command.
+
 config DEBUG_SPINLOCK_SLEEP
 	bool "Sleep-inside-spinlock checking"
 	help
 	  If you say Y here, various routines which may sleep will become very
 	  noisy if they are called with a spinlock held.	
 
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb/kgdb.txt file.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on KGDB
+	default  3f8
+	help
+	  Some systems (x86 family at this writing) allow the port
+	  address to be configured.  The number entered is assumed to be
+	  hex, don't put 0x in front of it.  The standard address are:
+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
+	  will tell you what you have.  It is good to test the serial
+	  connection with a live system before trying to debug.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 4
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config STACK_OVERFLOW_TEST
+	bool "Turn on kernel stack overflow testing?"
+	depends on KGDB
+	default n
+	help
+	  This option enables code in the front line interrupt handlers
+	  to check for kernel stack overflow on interrupts and system
+	  calls.  This is part of the kgdb code on x86 systems.
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
 	help
@@ -1294,6 +1476,19 @@
 	  on the VM subsystem for higher order allocations. This option
 	  will also use IRQ stacks to compensate for the reduced stackspace.
 
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
+
 config X86_FIND_SMP_CONFIG
 	bool
 	depends on X86_LOCAL_APIC || X86_VOYAGER
@@ -1332,12 +1527,6 @@
 	depends on X86_SMP || (X86_VOYAGER && SMP)
 	default y
 
-# std_resources is overridden for pc9800, but that's not
-# a currently selectable arch choice
-config X86_STD_RESOURCES
-	bool
-	default y
-
 config PC
 	bool
 	depends on X86 && !EMBEDDED
--- diff/arch/i386/Makefile	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/Makefile	2004-05-27 18:34:14.000000000 +0100
@@ -98,6 +98,9 @@
 # default subarch .h files
 mflags-y += -Iinclude/asm-i386/mach-default
 
+mflags-$(CONFIG_KGDB) += -gdwarf-2
+mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g')
+
 head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 libs-y 					+= arch/i386/lib/
--- diff/arch/i386/boot/compressed/misc.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/boot/compressed/misc.c	2004-05-27 18:34:14.000000000 +0100
@@ -87,12 +87,11 @@
  */
 static unsigned char *real_mode; /* Pointer to real-mode data */
 
-#define EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
+#define RM_EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
 #ifndef STANDARD_MEMORY_BIOS_CALL
-#define ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
+#define RM_ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
 #endif
-#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
-#define EDID_INFO   (*(struct edid_info *)(real_mode+0x440))
+#define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0))
 
 extern char input_data[];
 extern int input_len;
@@ -174,8 +173,8 @@
 	int x,y,pos;
 	char c;
 
-	x = SCREEN_INFO.orig_x;
-	y = SCREEN_INFO.orig_y;
+	x = RM_SCREEN_INFO.orig_x;
+	y = RM_SCREEN_INFO.orig_y;
 
 	while ( ( c = *s++ ) != '\0' ) {
 		if ( c == '\n' ) {
@@ -196,8 +195,8 @@
 		}
 	}
 
-	SCREEN_INFO.orig_x = x;
-	SCREEN_INFO.orig_y = y;
+	RM_SCREEN_INFO.orig_x = x;
+	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
 	outb_p(14, vidport);
@@ -306,9 +305,9 @@
 static void setup_normal_output_buffer(void)
 {
 #ifdef STANDARD_MEMORY_BIOS_CALL
-	if (EXT_MEM_K < 1024) error("Less than 2MB of memory");
+	if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory");
 #else
-	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory");
+	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
 #endif
 	output_data = (char *)0x100000; /* Points to 1M */
 	free_mem_end_ptr = (long)real_mode;
@@ -323,9 +322,11 @@
 {
 	high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
 #ifdef STANDARD_MEMORY_BIOS_CALL
-	if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
+	if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
 #else
-	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
+	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) <
+			(3*1024))
+		error("Less than 4MB of memory");
 #endif	
 	mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
 	low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
@@ -358,7 +359,7 @@
 {
 	real_mode = rmode;
 
-	if (SCREEN_INFO.orig_video_mode == 7) {
+	if (RM_SCREEN_INFO.orig_video_mode == 7) {
 		vidmem = (char *) 0xb0000;
 		vidport = 0x3b4;
 	} else {
@@ -366,8 +367,8 @@
 		vidport = 0x3d4;
 	}
 
-	lines = SCREEN_INFO.orig_video_lines;
-	cols = SCREEN_INFO.orig_video_cols;
+	lines = RM_SCREEN_INFO.orig_video_lines;
+	cols = RM_SCREEN_INFO.orig_video_cols;
 
 	if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
 	else setup_output_buffer_if_we_run_high(mv);
--- diff/arch/i386/kernel/Makefile	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/Makefile	2004-05-27 18:34:14.000000000 +0100
@@ -14,6 +14,7 @@
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
@@ -31,7 +32,6 @@
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
-obj-$(CONFIG_X86_STD_RESOURCES)	+= std_resources.o
 
 EXTRA_AFLAGS   := -traditional
 
--- diff/arch/i386/kernel/acpi/boot.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/acpi/boot.c	2004-05-27 18:34:14.000000000 +0100
@@ -28,7 +28,7 @@
 #include <linux/acpi.h>
 #include <linux/efi.h>
 #include <linux/irq.h>
-#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
 #include <asm/io_apic.h>
 #include <asm/apic.h>
 #include <asm/io.h>
@@ -437,6 +437,34 @@
 	return 0;
 }
 
+#ifdef CONFIG_ACPI_PCI
+unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low)
+{
+	static u16 irq_mask;
+	unsigned int irq;
+	extern void eisa_set_level_irq(unsigned int irq);
+
+	/*
+	 * Make sure all (legacy) PCI IRQs are set as level-triggered.
+	 */
+	if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
+		if ((gsi < 16) && !((1 << gsi) & irq_mask)) {
+			Dprintk(KERN_DEBUG PREFIX "Setting GSI %u as level-triggered\n", gsi);
+			irq_mask |= (1 << gsi);
+			eisa_set_level_irq(gsi);
+		}
+	}
+
+#ifdef CONFIG_X86_IO_APIC
+	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
+		mp_register_gsi(gsi, edge_level, active_high_low);
+	}
+#endif
+	acpi_gsi_to_irq(gsi, &irq);
+	return irq;
+}
+#endif	/* CONFIG_ACPI_PCI */
+
 static unsigned long __init
 acpi_scan_rsdp (
 	unsigned long		start,
--- diff/arch/i386/kernel/apic.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/apic.c	2004-05-27 18:34:14.000000000 +0100
@@ -31,7 +31,6 @@
 #include <asm/smp.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
-#include <asm/pgalloc.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
 #include <asm/hpet.h>
--- diff/arch/i386/kernel/cpu/common.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/cpu/common.c	2004-05-27 18:34:14.000000000 +0100
@@ -201,6 +201,8 @@
 {
 	struct cpuinfo_x86 *c = &boot_cpu_data;
 
+	c->x86_cache_alignment = 32;
+
 	if (!have_cpuid_p())
 		return;
 
@@ -213,8 +215,6 @@
 	get_cpu_vendor(c, 1);
 
 	c->x86 = 4;
-	c->x86_cache_alignment = 32;
-
 	if (c->cpuid_level >= 0x00000001) {
 		u32 junk, tfms, cap0, misc;
 		cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
--- diff/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c	2004-05-27 18:34:14.000000000 +0100
@@ -75,7 +75,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h> 
-#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/cpufreq.h>
--- diff/arch/i386/kernel/cpu/cpufreq/longhaul.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/cpu/cpufreq/longhaul.c	2004-05-27 18:34:14.000000000 +0100
@@ -18,7 +18,8 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h> 
+#include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
@@ -30,25 +31,25 @@
 
 #include "longhaul.h"
 
-#define DEBUG
-
-#ifdef DEBUG
-#define dprintk(msg...) printk(msg)
-#else
-#define dprintk(msg...) do { } while(0)
-#endif
-
 #define PFX "longhaul: "
 
 static unsigned int numscales=16, numvscales;
+static unsigned int fsb;
 static int minvid, maxvid;
 static int can_scale_voltage;
 static int vrmrev;
 
-
 /* Module parameters */
 static int dont_scale_voltage;
-static unsigned int fsb;
+static int debug;
+static int debug;
+
+static void dprintk(const char *msg, ...)
+{
+	if (debug == 1)
+		printk(msg);
+}
+
 
 #define __hlt()     __asm__ __volatile__("hlt": : :"memory")
 
@@ -118,8 +119,7 @@
 
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
-	dprintk (KERN_INFO PFX "FSB:%d Mult:%d.%dx\n", fsb,
-				mult/10, mult%10);
+	dprintk (KERN_INFO PFX "FSB:%d Mult:%d.%dx\n", fsb, mult/10, mult%10);
 
 	switch (longhaul_version) {
 	case 1:
@@ -167,16 +167,16 @@
 		longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
 		longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
 		longhaul.bits.EnableSoftBusRatio = 1;
-		
+
 		longhaul.bits.RevisionKey = 0x0;
-		
+
 		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
 		__hlt();
-		
+
 		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
 		longhaul.bits.EnableSoftBusRatio = 0;
 		longhaul.bits.RevisionKey = 0xf;
-		wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);		
+		wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
 		break;
 	}
 
@@ -276,26 +276,26 @@
 				break;
 		}
 		break;
-		
+
 	case 4:
 		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-		
+
 		//TODO: Nehemiah may have borken MaxMHzBR.
 		// need to extrapolate from FSB.
-		
+
 		invalue2 = longhaul.bits.MinMHzBR;
 		invalue = longhaul.bits.MaxMHzBR;
-		if (longhaul.bits.MaxMHzBR4) 
+		if (longhaul.bits.MaxMHzBR4)
 			invalue += 16;
 		maxmult=multipliers[invalue];
-		
+
 		maxmult=longhaul_get_cpu_mult();
-		
+
 		printk(KERN_INFO PFX " invalue: %ld  maxmult: %d \n", invalue, maxmult);
 		printk(KERN_INFO PFX " invalue2: %ld \n", invalue2);
-		
+
 		minmult=50;
-		
+
 		switch (longhaul.bits.MaxMHzFSB) {
 		case 0x0:	fsb=133;
 				break;
@@ -306,8 +306,8 @@
 		case 0x3:	fsb=66;
 				break;
 		}
-		
-		break;	
+
+		break;
 	}
 
 	dprintk (KERN_INFO PFX "MinMult=%d.%dx MaxMult=%d.%dx\n",
@@ -418,13 +418,13 @@
 			    unsigned int relation)
 {
 	unsigned int table_index = 0;
- 	unsigned int new_clock_ratio = 0;
+	unsigned int new_clock_ratio = 0;
 
 	if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))
 		return -EINVAL;
 
 	new_clock_ratio = longhaul_table[table_index].index & 0xFF;
- 
+
 	longhaul_setstate(new_clock_ratio);
 
 	return 0;
@@ -500,7 +500,6 @@
 			break;
 		}
 		break;
-		
 
 	default:
 		cpuname = "Unknown";
@@ -514,11 +513,11 @@
 	if (ret != 0)
 		return ret;
 
- 	if ((longhaul_version==2) && (dont_scale_voltage==0))
+	if ((longhaul_version==2) && (dont_scale_voltage==0))
 		longhaul_setup_voltagescaling();
 
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	policy->cur = calc_speed (longhaul_get_cpu_mult(), fsb);
 
 	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
@@ -542,14 +541,14 @@
 };
 
 static struct cpufreq_driver longhaul_driver = {
-	.verify 	= longhaul_verify,
-	.target 	= longhaul_target,
-	.get 		= longhaul_get,
-	.init		= longhaul_cpu_init,
-	.exit		= longhaul_cpu_exit,
-	.name		= "longhaul",
-	.owner		= THIS_MODULE,
-	.attr		= longhaul_attr,
+	.verify	= longhaul_verify,
+	.target	= longhaul_target,
+	.get	= longhaul_get,
+	.init	= longhaul_cpu_init,
+	.exit	= longhaul_cpu_exit,
+	.name	= "longhaul",
+	.owner	= THIS_MODULE,
+	.attr	= longhaul_attr,
 };
 
 static int __init longhaul_init (void)
@@ -560,12 +559,8 @@
 		return -ENODEV;
 
 	switch (c->x86_model) {
-	case 6 ... 8:
+	case 6 ... 9:
 		return cpufreq_register_driver(&longhaul_driver);
-	case 9:
-		printk (KERN_INFO PFX "Nehemiah unsupported: Waiting on working silicon "
-						"from VIA before this is usable.\n");
-		break;
 	default:
 		printk (KERN_INFO PFX "Unknown VIA CPU. Contact davej@codemonkey.org.uk\n");
 	}
@@ -579,7 +574,11 @@
 	kfree(longhaul_table);
 }
 
-MODULE_PARM (dont_scale_voltage, "i");
+module_param (dont_scale_voltage, int, 0644);
+MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor");
+
+module_param (debug, int, 0644);
+MODULE_PARM_DESC(debug, "Dump debugging information.");
 
 MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
 MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
--- diff/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	2004-05-27 18:34:14.000000000 +0100
@@ -27,7 +27,6 @@
 #include <linux/smp.h>
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
-#include <linux/sched.h>
 
 #include <asm/processor.h> 
 #include <asm/msr.h>
@@ -35,7 +34,7 @@
 
 #include "speedstep-lib.h"
 
-#define PFX	"cpufreq: "
+#define PFX	"p4-clockmod: "
 
 /*
  * Duty Cycle (3bits), note DC_DISABLE is not specified in
--- diff/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	2004-05-27 18:34:14.000000000 +0100
@@ -16,7 +16,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/module.h> 
+#include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/cpufreq.h>
@@ -86,7 +86,7 @@
 /* divide by 10 to get FID. */
 static int fid_codes[32] = {
     110, 115, 120, 125, 50, 55, 60, 65,
-    70, 75, 80, 85, 90, 95, 100, 105, 
+    70, 75, 80, 85, 90, 95, 100, 105,
     30, 190, 40, 200, 130, 135, 140, 210,
     150, 225, 160, 165, 170, 180, -1, -1,
 };
@@ -144,6 +144,11 @@
 	}
 
 	cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
+
+	/* Check we can actually do something before we say anything.*/
+	if (!(edx & (1 << 1 | 1 << 2)))
+		return 0;
+
 	printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
 
 	if (edx & 1 << 1) {
@@ -159,11 +164,6 @@
 		can_scale_vid=1;
 	}
 
-	if (!(edx & (1 << 1 | 1 << 2))) {
-		printk ("nothing.\n");
-		return 0;
-	}
-
 	printk (".\n");
 	return 1;
 }
--- diff/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2004-05-27 18:34:14.000000000 +0100
@@ -553,7 +553,7 @@
 		printk(KERN_ERR PFX "no p states to transition\n");
 		return -ENODEV;
 	}
-                                                                                                    
+
 	if (check_pst_table(data, pst, maxvid))
 		return -EINVAL;
 
@@ -736,9 +736,9 @@
 		/* verify only 1 entry from the lo frequency table */
 		if ((fid < HI_FID_TABLE_BOTTOM) && (cntlofreq++)) {
 			printk(KERN_ERR PFX "Too many lo freq table entries\n");
-			goto err_out;
+			goto err_out_mem;
 		}
-                                                                                                            
+
 		if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
 			printk(KERN_INFO PFX "invalid freq entries %u kHz vs. %u kHz\n",
 				powernow_table[i].frequency,
@@ -757,12 +757,16 @@
 	print_basics(data);
 	powernow_k8_acpi_pst_values(data, 0);
 	return 0;
+
+err_out_mem:
+	kfree(powernow_table);
+
 err_out:
 	acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
 
 	/* data->acpi_data.state_count informs us at ->exit() whether ACPI was used */
 	data->acpi_data.state_count = 0;
-                                                                                                            
+
 	return -ENODEV;
 }
 
@@ -1047,7 +1051,7 @@
 	if (query_current_values_with_pending_wait(data))
 		goto out;
 
-	khz = find_khz_freq_from_fid(data->currfid);	
+	khz = find_khz_freq_from_fid(data->currfid);
 
  out:
 	preempt_enable_no_resched();
--- diff/arch/i386/kernel/dmi_scan.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/dmi_scan.c	2004-05-27 18:34:14.000000000 +0100
@@ -401,6 +401,23 @@
 }
 
 /*
+ * HP Proliant 8500 systems can't use i8042 in mux mode,
+ * or they instantly reboot.
+ */
+#ifdef CONFIG_SERIO_I8042
+extern unsigned int i8042_nomux;
+static __init int set_8042_nomux(struct dmi_blacklist *d)
+{
+	if (i8042_nomux == 0)
+	{
+		i8042_nomux = 1;
+		printk(KERN_INFO "Disabling i8042 mux mode\n");
+	}
+	return 0;
+}
+#endif
+
+/*
  * This bios swaps the APM minute reporting bytes over (Many sony laptops
  * have this problem).
  */
@@ -924,6 +941,14 @@
 			MATCH(DMI_PRODUCT_NAME, "ProLiant ML350 G3"),
 			NO_MATCH, NO_MATCH }},
 
+#ifdef CONFIG_SERIO_I8042
+	{ set_8042_nomux, "Compaq Proliant 8500", {
+			MATCH(DMI_SYS_VENDOR, "Compaq"),
+			MATCH(DMI_PRODUCT_NAME , "ProLiant"),
+			MATCH(DMI_PRODUCT_VERSION, "8500"),
+			NO_MATCH }},
+#endif
+
 	{ force_acpi_ht, "Compaq Workstation W8000", {
 			MATCH(DMI_SYS_VENDOR, "Compaq"),
 			MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
--- diff/arch/i386/kernel/efi.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/efi.c	2004-05-27 18:34:14.000000000 +0100
@@ -37,7 +37,6 @@
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/desc.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 #define EFI_DEBUG	0
--- diff/arch/i386/kernel/entry.S	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/entry.S	2004-05-27 18:34:14.000000000 +0100
@@ -48,6 +48,18 @@
 #include <asm/smp.h>
 #include <asm/page.h>
 #include "irq_vectors.h"
+        /* We do not recover from a stack overflow, but at least
+         * we know it happened and should be able to track it down.
+         */
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#define STACK_OVERFLOW_TEST \
+        testl $(THREAD_SIZE - 512),%esp;    \
+        jnz   10f;            \
+        call  stack_overflow; \
+10:
+#else
+#define STACK_OVERFLOW_TEST
+#endif
 
 #define nr_syscalls ((syscall_table_size)/4)
 
@@ -94,7 +106,8 @@
 	pushl %ebx; \
 	movl $(__USER_DS), %edx; \
 	movl %edx, %ds; \
-	movl %edx, %es;
+	movl %edx, %es; \
+        STACK_OVERFLOW_TEST
 
 #define RESTORE_INT_REGS \
 	popl %ebx;	\
@@ -294,6 +307,19 @@
 	testw $_TIF_ALLWORK_MASK, %cx	# current->work
 	jne syscall_exit_work
 restore_all:
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
+	movb CS(%esp), %al
+	testl $(VM_MASK | 3), %eax
+	jz resume_kernelX		# returning to kernel or vm86-space
+
+	cmpl $0,TI_PRE_COUNT(%ebx)	# non-zero preempt_count ?
+	jz resume_kernelX
+
+        int $3
+
+resume_kernelX:
+#endif
 	RESTORE_ALL
 
 	# perform work that needs to be done immediately before resumption
@@ -348,7 +374,7 @@
 	# perform syscall exit tracing
 	ALIGN
 syscall_exit_work:
-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %cl
+	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
 	jz work_pending
 	sti				# could let do_syscall_trace() call
 					# schedule() instead
--- diff/arch/i386/kernel/i386_ksyms.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/i386_ksyms.c	2004-05-27 18:34:14.000000000 +0100
@@ -29,7 +29,6 @@
 #include <asm/mmx.h>
 #include <asm/desc.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/nmi.h>
 #include <asm/ist.h>
--- diff/arch/i386/kernel/i8259.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/i8259.c	2004-05-27 18:34:14.000000000 +0100
@@ -317,16 +317,11 @@
  * be shot.
  */
  
-/*
- * =PC9800NOTE= In NEC PC-9800, we use irq8 instead of irq13!
- */
 
 static irqreturn_t math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
 {
 	extern void math_error(void *);
-#ifndef CONFIG_X86_PC9800
 	outb(0,0xF0);
-#endif
 	if (ignore_fpu_irq || !boot_cpu_data.hard_math)
 		return IRQ_NONE;
 	math_error((void *)regs->eip);
--- diff/arch/i386/kernel/init_task.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/init_task.c	2004-05-27 18:34:14.000000000 +0100
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/i386/kernel/io_apic.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/io_apic.c	2004-05-27 18:34:14.000000000 +0100
@@ -41,8 +41,6 @@
 
 #include "io_ports.h"
 
-#undef APIC_LOCKUP_DEBUG
-
 #define APIC_LOCKUP_DEBUG
 
 static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
@@ -127,8 +125,7 @@
 	}
 }
 
-/* mask = 1 */
-static void __mask_IO_APIC_irq (unsigned int irq)
+static inline void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable)
 {
 	int pin;
 	struct irq_pin_list *entry = irq_2_pin + irq;
@@ -139,71 +136,39 @@
 		if (pin == -1)
 			break;
 		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		io_apic_modify(entry->apic, 0x10 + pin*2, reg |= 0x00010000);
+		reg &= ~disable;
+		reg |= enable;
+		io_apic_modify(entry->apic, 0x10 + pin*2, reg);
 		if (!entry->next)
 			break;
 		entry = irq_2_pin + entry->next;
 	}
-	io_apic_sync(entry->apic);
 }
 
-/* mask = 0 */
-static void __unmask_IO_APIC_irq (unsigned int irq)
+/* mask = 1 */
+static void __mask_IO_APIC_irq (unsigned int irq)
 {
-	int pin;
 	struct irq_pin_list *entry = irq_2_pin + irq;
+	__modify_IO_APIC_irq(irq, 0x00010000, 0);
+	io_apic_sync(entry->apic);	/* Is it needed? Or do others need it too? */
+}
 
-	for (;;) {
-		unsigned int reg;
-		pin = entry->pin;
-		if (pin == -1)
-			break;
-		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		io_apic_modify(entry->apic, 0x10 + pin*2, reg &= 0xfffeffff);
-		if (!entry->next)
-			break;
-		entry = irq_2_pin + entry->next;
-	}
+/* mask = 0 */
+static void __unmask_IO_APIC_irq (unsigned int irq)
+{
+	__modify_IO_APIC_irq(irq, 0, 0x00010000);
 }
 
 /* mask = 1, trigger = 0 */
 static void __mask_and_edge_IO_APIC_irq (unsigned int irq)
 {
-	int pin;
-	struct irq_pin_list *entry = irq_2_pin + irq;
-
-	for (;;) {
-		unsigned int reg;
-		pin = entry->pin;
-		if (pin == -1)
-			break;
-		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		reg = (reg & 0xffff7fff) | 0x00010000;
-		io_apic_modify(entry->apic, 0x10 + pin*2, reg);
-		if (!entry->next)
-			break;
-		entry = irq_2_pin + entry->next;
-	}
+	__modify_IO_APIC_irq(irq, 0x00010000, 0x00008000);
 }
 
 /* mask = 0, trigger = 1 */
 static void __unmask_and_level_IO_APIC_irq (unsigned int irq)
 {
-	int pin;
-	struct irq_pin_list *entry = irq_2_pin + irq;
-
-	for (;;) {
-		unsigned int reg;
-		pin = entry->pin;
-		if (pin == -1)
-			break;
-		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		reg = (reg & 0xfffeffff) | 0x00008000;
-		io_apic_modify(entry->apic, 0x10 + pin*2, reg);
-		if (!entry->next)
-			break;
-		entry = irq_2_pin + entry->next;
-	}
+	__modify_IO_APIC_irq(irq, 0x00008000, 0x00010000);
 }
 
 static void mask_IO_APIC_irq (unsigned int irq)
@@ -853,7 +818,7 @@
  * we need to reprogram the ioredtbls to cater for the cpus which have come online
  * so mask in all cases should simply be TARGET_CPUS
  */
-void __init setup_ioapic_dest(cpumask_t mask)
+void __init setup_ioapic_dest(void)
 {
 	int pin, ioapic, irq, irq_entry;
 
@@ -866,7 +831,7 @@
 			if (irq_entry == -1)
 				continue;
 			irq = pin_2_irq(irq_entry, ioapic, pin);
-			set_ioapic_affinity_irq(irq, mask);
+			set_ioapic_affinity_irq(irq, TARGET_CPUS);
 		}
 
 	}
--- diff/arch/i386/kernel/irq.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/irq.c	2004-05-27 18:34:14.000000000 +0100
@@ -41,7 +41,6 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/delay.h>
 #include <asm/desc.h>
 #include <asm/irq.h>
@@ -570,6 +569,8 @@
 
 	irq_exit();
 
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
@@ -1117,8 +1118,8 @@
 
 
 #ifdef CONFIG_4KSTACKS
-static char softirq_stack[NR_CPUS * THREAD_SIZE]  __attribute__((__aligned__(THREAD_SIZE)));
-static char hardirq_stack[NR_CPUS * THREAD_SIZE]  __attribute__((__aligned__(THREAD_SIZE)));
+static char softirq_stack[NR_CPUS * THREAD_SIZE]  __attribute__((__aligned__(THREAD_SIZE), __section__(".bss.page_aligned")));
+static char hardirq_stack[NR_CPUS * THREAD_SIZE]  __attribute__((__aligned__(THREAD_SIZE), __section__(".bss.page_aligned")));
 
 /*
  * allocate per-cpu stacks for hardirq and for softirq processing
--- diff/arch/i386/kernel/mpparse.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/mpparse.c	2004-05-27 18:34:14.000000000 +0100
@@ -28,7 +28,6 @@
 #include <asm/acpi.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
-#include <asm/pgalloc.h>
 #include <asm/io_apic.h>
 
 #include <mach_apic.h>
@@ -1025,96 +1024,56 @@
 	}
 }
 
-extern FADT_DESCRIPTOR acpi_fadt;
-
-#ifdef CONFIG_ACPI_PCI
-
 int (*platform_rename_gsi)(int ioapic, int gsi);
 
-void __init mp_parse_prt (void)
+void mp_register_gsi (u32 gsi, int edge_level, int active_high_low)
 {
-	struct list_head	*node = NULL;
-	struct acpi_prt_entry	*entry = NULL;
 	int			ioapic = -1;
 	int			ioapic_pin = 0;
-	int			gsi = 0;
 	int			idx, bit = 0;
-	int			edge_level = 0;
-	int			active_high_low = 0;
 
-	/*
-	 * Parsing through the PCI Interrupt Routing Table (PRT) and program
-	 * routing for all entries.
-	 */
-	list_for_each(node, &acpi_prt.entries) {
-		entry = list_entry(node, struct acpi_prt_entry, node);
+#ifdef CONFIG_ACPI_BUS
+	/* Don't set up the ACPI SCI because it's already set up */
+	if (acpi_fadt.sci_int == gsi)
+		return;
+#endif
 
-		/* Need to get gsi for dynamic entry */
-		if (entry->link.handle) {
-			gsi = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
-			if (!gsi)
-				continue;
-		}
-		else {
-			/* Hardwired GSI. Assume PCI standard settings */
-			gsi = entry->link.index;
-			edge_level = 1;
-			active_high_low = 1;
-		}
+	ioapic = mp_find_ioapic(gsi);
+	if (ioapic < 0) {
+		printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
+		return;
+	}
 
-		/* Don't set up the ACPI SCI because it's already set up */
-                if (acpi_fadt.sci_int == gsi) {
-			/* we still need to set entry's irq */
-			acpi_gsi_to_irq(gsi, &entry->irq);
-			continue;
-                }
-	
-		ioapic = mp_find_ioapic(gsi);
-		if (ioapic < 0)
-			continue;
-		ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
-
-		if (platform_rename_gsi)
-			gsi = platform_rename_gsi(ioapic, gsi);
-
-		/* 
-		 * Avoid pin reprogramming.  PRTs typically include entries  
-		 * with redundant pin->gsi mappings (but unique PCI devices);
-		 * we only only program the IOAPIC on the first.
-		 */
-		bit = ioapic_pin % 32;
-		idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
-		if (idx > 3) {
-			printk(KERN_ERR "Invalid reference to IOAPIC pin "
-				"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
-				ioapic_pin);
-			continue;
-		}
-		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
-			Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
-				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
-			acpi_gsi_to_irq(gsi, &entry->irq);
-			continue;
-		}
+	ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
 
-		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
+	if (platform_rename_gsi)
+		gsi = platform_rename_gsi(ioapic, gsi);
 
-		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
-			acpi_gsi_to_irq(gsi, &entry->irq);
-		}
-		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d %s %s\n",
-			entry->id.segment, entry->id.bus,
-			entry->id.device, ('A' + entry->pin),
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
-			entry->irq, edge_level ? "level" : "edge",
-			active_high_low ? "low" : "high");
+	/* 
+	 * Avoid pin reprogramming.  PRTs typically include entries  
+	 * with redundant pin->gsi mappings (but unique PCI devices);
+	 * we only program the IOAPIC on the first.
+	 */
+	bit = ioapic_pin % 32;
+	idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
+	if (idx > 3) {
+		printk(KERN_ERR "Invalid reference to IOAPIC pin "
+			"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
+			ioapic_pin);
+		return;
+	}
+	if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+		Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
+			mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+		return;
 	}
 
-	print_IO_APIC();
+	mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
 
-	return;
+	io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
+		    edge_level == ACPI_EDGE_SENSITIVE ? 0 : 1,
+		    active_high_low == ACPI_ACTIVE_HIGH ? 0 : 1);
 }
 
-#endif /*CONFIG_ACPI_PCI*/
 #endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/
 #endif /*CONFIG_ACPI_BOOT*/
--- diff/arch/i386/kernel/nmi.c	2004-05-27 13:41:11.000000000 +0100
+++ source/arch/i386/kernel/nmi.c	2004-05-27 18:34:14.000000000 +0100
@@ -31,7 +31,16 @@
 #include <asm/mpspec.h>
 #include <asm/nmi.h>
 
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#ifdef CONFIG_SMP
+unsigned int nmi_watchdog = NMI_IO_APIC;
+#else
+unsigned int nmi_watchdog = NMI_LOCAL_APIC;
+#endif
+#else
 unsigned int nmi_watchdog = NMI_NONE;
+#endif
 static unsigned int nmi_hz = HZ;
 static unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
 static unsigned int nmi_p4_cccr_val;
@@ -458,6 +467,9 @@
 	for (i = 0; i < NR_CPUS; i++)
 		alert_counter[i] = 0;
 }
+#ifdef CONFIG_KGDB
+int tune_watchdog = 5*HZ;
+#endif
 
 void nmi_watchdog_tick (struct pt_regs * regs)
 {
@@ -471,12 +483,24 @@
 
 	sum = irq_stat[cpu].apic_timer_irqs;
 
+#ifdef CONFIG_KGDB
+ 	if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) {
+
+#else
 	if (last_irq_sums[cpu] == sum) {
+#endif
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
+#ifdef CONFIG_KGDB
+                if (alert_counter[cpu] == tune_watchdog) {
+                        kgdb_handle_exception(2, SIGPWR, 0, regs);
+                        last_irq_sums[cpu] = sum;
+                        alert_counter[cpu] = 0;
+                }
+#endif
 		if (alert_counter[cpu] == 5*nmi_hz) {
 			spin_lock(&nmi_print_lock);
 			/*
--- diff/arch/i386/kernel/process.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/i386/kernel/process.c	2004-05-27 18:34:14.000000000 +0100
@@ -202,6 +202,10 @@
 	if (!strncmp(str, "poll", 4)) {
 		printk("using polling idle threads.\n");
 		pm_idle = poll_idle;
+#ifdef CONFIG_SMP
+		if (smp_num_siblings > 1)
+			printk("WARNING: polling idle and HT enabled, performance may degrade.\n");
+#endif
 	} else if (!strncmp(str, "halt", 4)) {
 		printk("using halt in idle threads.\n");
 		pm_idle = default_idle;
--- diff/arch/i386/kernel/ptrace.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/i386/kernel/ptrace.c	2004-05-27 18:34:14.000000000 +0100
@@ -147,6 +147,7 @@
 { 
 	long tmp;
 
+	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 	tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
 	put_stack_long(child, EFL_OFFSET, tmp);
 }
@@ -369,6 +370,7 @@
 		else {
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		}
+		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 		child->exit_code = data;
 	/* make sure the single step bit is not set. */
 		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
@@ -390,6 +392,7 @@
 		if (child->state == TASK_ZOMBIE)	/* already dead */
 			break;
 		child->exit_code = SIGKILL;
+		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 		/* make sure the single step bit is not set. */
 		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
 		put_stack_long(child, EFL_OFFSET, tmp);
@@ -410,6 +413,7 @@
 		}
 		tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
 		put_stack_long(child, EFL_OFFSET, tmp);
+		set_tsk_thread_flag(child, TIF_SINGLESTEP);
 		child->exit_code = data;
 		/* give it a chance to run. */
 		wake_up_process(child);
@@ -534,7 +538,8 @@
 			audit_syscall_exit(current, regs->eax);
 	}
 
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
+	    !test_thread_flag(TIF_SINGLESTEP))
 		return;
 	if (!(current->ptrace & PT_PTRACED))
 		return;
--- diff/arch/i386/kernel/setup.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/i386/kernel/setup.c	2004-05-27 18:34:14.000000000 +0100
@@ -47,7 +47,7 @@
 #include <asm/sections.h>
 #include <asm/io_apic.h>
 #include <asm/ist.h>
-#include <asm/std_resources.h>
+#include <asm/io.h>
 #include "setup_arch_pre.h"
 
 /* This value is set up by the early boot code to point to the value
@@ -129,12 +129,206 @@
 #define RAMDISK_LOAD_FLAG		0x4000	
 
 static char command_line[COMMAND_LINE_SIZE];
-       char saved_command_line[COMMAND_LINE_SIZE];
 
 unsigned char __initdata boot_params[PARAM_SIZE];
 
-static struct resource code_resource = { "Kernel code", 0x100000, 0 };
-static struct resource data_resource = { "Kernel data", 0, 0 };
+static struct resource data_resource = {
+	.name	= "Kernel data",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource code_resource = {
+	.name	= "Kernel code",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource system_rom_resource = {
+	.name	= "System ROM",
+	.start	= 0xf0000,
+	.end	= 0xfffff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+static struct resource extension_rom_resource = {
+	.name	= "Extension ROM",
+	.start	= 0xe0000,
+	.end	= 0xeffff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+static struct resource adapter_rom_resources[] = { {
+	.name 	= "Adapter ROM",
+	.start	= 0xc8000,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+} };
+
+#define ADAPTER_ROM_RESOURCES \
+	(sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
+
+static struct resource video_rom_resource = {
+	.name 	= "Video ROM",
+	.start	= 0xc0000,
+	.end	= 0xc7fff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+static struct resource video_ram_resource = {
+	.name	= "Video RAM area",
+	.start	= 0xa0000,
+	.end	= 0xbffff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource standard_io_resources[] = { {
+	.name	= "dma1",
+	.start	= 0x0000,
+	.end	= 0x001f,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "pic1",
+	.start	= 0x0020,
+	.end	= 0x0021,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "timer",
+	.start	= 0x0040,
+	.end	= 0x005f,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "keyboard",
+	.start	= 0x0060,
+	.end	= 0x006f,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "dma page reg",
+	.start	= 0x0080,
+	.end	= 0x008f,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "pic2",
+	.start	= 0x00a0,
+	.end	= 0x00a1,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "dma2",
+	.start	= 0x00c0,
+	.end	= 0x00df,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "fpu",
+	.start	= 0x00f0,
+	.end	= 0x00ff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+} };
+
+#define STANDARD_IO_RESOURCES \
+	(sizeof standard_io_resources / sizeof standard_io_resources[0])
+
+#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
+
+static int __init romchecksum(unsigned char *rom, unsigned long length)
+{
+	unsigned char *p, sum = 0;
+
+	for (p = rom; p < rom + length; p++)
+		sum += *p;
+	return sum == 0;
+}
+
+static void __init probe_roms(void)
+{
+	unsigned long start, length, upper;
+	unsigned char *rom;
+	int	      i;
+
+	/* video rom */
+	upper = adapter_rom_resources[0].start;
+	for (start = video_rom_resource.start; start < upper; start += 2048) {
+		rom = isa_bus_to_virt(start);
+		if (!romsignature(rom))
+			continue;
+
+		video_rom_resource.start = start;
+
+		/* 0 < length <= 0x7f * 512, historically */
+		length = rom[2] * 512;
+
+		/* if checksum okay, trust length byte */
+		if (length && romchecksum(rom, length))
+			video_rom_resource.end = start + length - 1;
+
+		request_resource(&iomem_resource, &video_rom_resource);
+		break;
+	}
+
+	start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
+	if (start < upper)
+		start = upper;
+
+	/* system rom */
+	request_resource(&iomem_resource, &system_rom_resource);
+	upper = system_rom_resource.start;
+
+	/* check for extension rom (ignore length byte!) */
+	rom = isa_bus_to_virt(extension_rom_resource.start);
+	if (romsignature(rom)) {
+		length = extension_rom_resource.end - extension_rom_resource.start + 1;
+		if (romchecksum(rom, length)) {
+			request_resource(&iomem_resource, &extension_rom_resource);
+			upper = extension_rom_resource.start;
+		}
+	}
+
+	/* check for adapter roms on 2k boundaries */
+	for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
+		rom = isa_bus_to_virt(start);
+		if (!romsignature(rom))
+			continue;
+
+		/* 0 < length <= 0x7f * 512, historically */
+		length = rom[2] * 512;
+
+		/* but accept any length that fits if checksum okay */
+		if (!length || start + length > upper || !romchecksum(rom, length))
+			continue;
+
+		adapter_rom_resources[i].start = start;
+		adapter_rom_resources[i].end = start + length - 1;
+		request_resource(&iomem_resource, &adapter_rom_resources[i]);
+
+		start = adapter_rom_resources[i++].end & ~2047UL;
+	}
+}
 
 static void __init limit_regions(unsigned long long size)
 {
@@ -948,6 +1142,7 @@
 static void __init register_memory(unsigned long max_low_pfn)
 {
 	unsigned long low_mem_size;
+	int	      i;
 
 	if (efi_enabled)
 		efi_initialize_iomem_resources(&code_resource, &data_resource);
@@ -955,10 +1150,11 @@
 		legacy_init_iomem_resources(&code_resource, &data_resource);
 
 	/* EFI systems may still have VGA */
-	request_graphics_resource();
+	request_resource(&iomem_resource, &video_ram_resource);
 
 	/* request I/O space for devices used on all i[345]86 PCs */
-	request_standard_io_resources();
+	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+		request_resource(&ioport_resource, &standard_io_resources[i]);
 
 	/* Tell the PCI layer not to allocate too close to the RAM area.. */
 	low_mem_size = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff;
--- diff/arch/i386/kernel/smp.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/i386/kernel/smp.c	2004-05-27 18:34:15.000000000 +0100
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 
 #include <asm/mtrr.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <mach_ipi.h>
 #include <mach_apic.h>
@@ -466,7 +465,17 @@
 {
 	on_each_cpu(do_flush_tlb_all, 0, 1, 1);
 }
-
+#ifdef CONFIG_KGDB
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+void smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
--- diff/arch/i386/kernel/smpboot.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/i386/kernel/smpboot.c	2004-05-27 18:34:15.000000000 +0100
@@ -47,7 +47,6 @@
 
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
@@ -1369,8 +1368,7 @@
 void __init smp_cpus_done(unsigned int max_cpus)
 {
 #ifdef CONFIG_X86_IO_APIC
-	cpumask_t targets = CPU_MASK_ALL;
-	setup_ioapic_dest(targets);
+	setup_ioapic_dest();
 #endif
 	zap_low_mappings();
 }
--- diff/arch/i386/kernel/time_hpet.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/time_hpet.c	2004-05-27 18:34:15.000000000 +0100
@@ -21,6 +21,7 @@
 #include <linux/config.h>
 
 #include <asm/hpet.h>
+#include <linux/hpet.h>
 
 unsigned long hpet_period;	/* fsecs / HPET clock */
 unsigned long hpet_tick;	/* hpet clks count per tick */
@@ -135,6 +136,51 @@
 	hpet_writel(cfg, HPET_CFG);
 
 	use_hpet = 1;
+
+#ifdef	CONFIG_HPET
+	{
+		struct hpet_data	hd;
+		unsigned int 		ntimer;
+
+		memset(&hd, 0, sizeof (hd));
+
+		ntimer = hpet_readl(HPET_ID);
+		ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
+		ntimer++;
+
+		/*
+		 * Register with driver.
+		 * Timer0 and Timer1 is used by platform.
+		 */
+		hd.hd_address = hpet_virt_address;
+		hd.hd_nirqs = ntimer;
+		hd.hd_flags = HPET_DATA_PLATFORM;
+#ifndef	CONFIG_HPET_EMULATE_RTC
+		hd.hd_state = 0x1;
+#else
+		hd.hd_state = 0x3;
+#endif
+		hd.hd_irq[0] = HPET_LEGACY_8254;
+		hd.hd_irq[1] = HPET_LEGACY_RTC;
+		if (ntimer > 2) {
+			struct hpet		*hpet;
+			struct hpet_timer	*timer;
+			int			i;
+
+			hpet = (struct hpet *) hpet_virt_address;
+
+			for (i = 2, timer = &hpet->hpet_timers[2]; i < ntimer;
+				timer++, i++)
+				hd.hd_irq[i] = (timer->hpet_config &
+					Tn_INT_ROUTE_CNF_MASK) >>
+					Tn_INT_ROUTE_CNF_SHIFT;
+
+		}
+
+		hpet_alloc(&hd);
+	}
+#endif
+
 #ifdef CONFIG_X86_LOCAL_APIC
 	wait_timer_tick = wait_hpet_tick;
 #endif
--- diff/arch/i386/kernel/traps.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/i386/kernel/traps.c	2004-05-27 18:34:15.000000000 +0100
@@ -47,7 +47,6 @@
 #include <asm/nmi.h>
 
 #include <asm/smp.h>
-#include <asm/pgalloc.h>
 #include <asm/arch_hooks.h>
 
 #include <linux/irq.h>
@@ -103,8 +102,42 @@
 	return 1;
 }
 
+#ifdef CONFIG_KGDB
+extern void sysenter_entry(void);
+#include <asm/kgdb.h>
+#include <linux/init.h>
+void set_intr_gate(unsigned int n, void *addr);
+static void set_intr_usr_gate(unsigned int n, void *addr);
+/*
+ * Should be able to call this breakpoint() very early in
+ * bring up.  Just hard code the call where needed.
+ * The breakpoint() code is here because set_?_gate() functions
+ * are local (static) to trap.c.  They need be done only once,
+ * but it does not hurt to do them over.
+ */
+void breakpoint(void)
+{
+        set_intr_usr_gate(3,&int3); /* disable ints on trap */
+	set_intr_gate(1,&debug);
+	set_intr_gate(14,&page_fault);
+
+        BREAKPOINT;
+}
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
+    {									\
+	if (!user_mode(regs)  ) \
+	{								\
+		kgdb_handle_exception(trapnr, signr, error_code, regs);	\
+		after;							\
+	} else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \
+    }
+#else
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
+#endif
+
+
 #ifdef CONFIG_FRAME_POINTER
-void print_context_stack(struct task_struct *task, unsigned long *stack,
+static void print_context_stack(struct task_struct *task, unsigned long *stack,
 			 unsigned long ebp)
 {
 	unsigned long addr;
@@ -118,7 +151,7 @@
 	}
 }
 #else
-void print_context_stack(struct task_struct *task, unsigned long *stack,
+static void print_context_stack(struct task_struct *task, unsigned long *stack,
 			 unsigned long ebp)
 {
 	unsigned long addr;
@@ -126,8 +159,9 @@
 	while (!kstack_end(stack)) {
 		addr = *stack++;
 		if (kernel_text_address(addr)) {
-			printk(" [<%08lx>] ", addr);
-			print_symbol("%s\n", addr);
+			printk(" [<%08lx>]", addr);
+			print_symbol(" %s", addr);
+			printk("\n");
 		}
 	}
 }
@@ -217,7 +251,7 @@
 		ss = regs->xss & 0xffff;
 	}
 	print_modules();
-	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx"
+	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s VLI\nEFLAGS: %08lx"
 			"   (%s) \n",
 		smp_processor_id(), 0xffff & regs->xcs, regs->eip,
 		print_tainted(), regs->eflags, UTS_RELEASE);
@@ -235,23 +269,25 @@
 	 * time of the fault..
 	 */
 	if (in_kernel) {
+		u8 *eip;
 
 		printk("\nStack: ");
 		show_stack(NULL, (unsigned long*)esp);
 
 		printk("Code: ");
-		if(regs->eip < PAGE_OFFSET)
-			goto bad;
 
-		for(i=0;i<20;i++)
-		{
+		eip = (u8 *)regs->eip - 43;
+		for (i = 0; i < 64; i++, eip++) {
 			unsigned char c;
-			if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
-bad:
+
+			if (eip < (u8 *)PAGE_OFFSET || __get_user(c, eip)) {
 				printk(" Bad EIP value.");
 				break;
 			}
-			printk("%02x ", c);
+			if (eip == (u8 *)regs->eip)
+				printk("<%02x> ", c);
+			else
+				printk("%02x ", c);
 		}
 	}
 	printk("\n");
@@ -319,6 +355,15 @@
 #endif
 	if (nl)
 		printk("\n");
+#ifdef CONFIG_KGDB
+	/* This is about the only place we want to go to kgdb even if in
+	 * user mode.  But we must go in via a trap so within kgdb we will
+	 * always be in kernel mode.
+	 */
+	if (user_mode(regs))
+		BREAKPOINT;
+#endif
+ 	CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
 	show_registers(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
@@ -388,6 +433,7 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -405,7 +451,9 @@
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\
 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+	return; \
 }
 
 #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -452,8 +500,10 @@
 	return;
 
 gp_in_kernel:
-	if (!fixup_exception(regs))
+	if (!fixup_exception(regs)){
+ 		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
 		die("general protection fault", regs, error_code);
+	}
 }
 
 static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
@@ -615,8 +665,18 @@
 		 * allowing programs to debug themselves without the ptrace()
 		 * interface.
 		 */
+#ifdef CONFIG_KGDB
+		/*
+		 * I think this is the only "real" case of a TF in the kernel
+		 * that really belongs to user space.  Others are
+		 * "Ours all ours!"
+		 */
+		if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry))
+			goto clear_TF_reenable;
+#else
 		if ((regs->xcs & 3) == 0)
 			goto clear_TF_reenable;
+#endif
 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
 			goto clear_TF;
 	}
@@ -628,6 +688,17 @@
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	
+#ifdef CONFIG_KGDB
+        /*
+	 * If this is a kernel mode trap, we need to reset db7 to allow us
+	 * to continue sanely ALSO skip the signal delivery
+         */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+        /* if not kernel, allow ints but only if they were on */
+       if ( regs->eflags & 0x200) local_irq_enable();
+#endif
 	/* If this is a kernel mode trap, save the user PC on entry to 
 	 * the kernel, that's what the debugger can make sense of.
 	 */
@@ -642,6 +713,7 @@
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
@@ -890,6 +962,12 @@
 {
 	_set_gate(a,12,3,addr,__KERNEL_CS);
 }
+#ifdef CONFIG_KGDB
+void set_intr_usr_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n,14,3,addr,__KERNEL_CS);
+}
+#endif
 
 static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
 {
@@ -912,7 +990,11 @@
 	set_trap_gate(0,&divide_error);
 	set_intr_gate(1,&debug);
 	set_intr_gate(2,&nmi);
+#ifndef CONFIG_KGDB
 	set_system_gate(3,&int3);	/* int3-5 can be called from all */
+#else
+	set_intr_usr_gate(3,&int3);	/* int3-5 can be called from all */
+#endif
 	set_system_gate(4,&overflow);
 	set_system_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
--- diff/arch/i386/kernel/vm86.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/vm86.c	2004-05-27 18:34:15.000000000 +0100
@@ -44,7 +44,6 @@
 #include <linux/ptrace.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/io.h>
 #include <asm/tlbflush.h>
 #include <asm/irq.h>
--- diff/arch/i386/lib/Makefile	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/lib/Makefile	2004-05-27 18:34:15.000000000 +0100
@@ -9,3 +9,4 @@
 
 lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB) += kgdb_serial.o
--- diff/arch/i386/lib/dec_and_lock.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/lib/dec_and_lock.c	2004-05-27 18:34:15.000000000 +0100
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	int counter;
@@ -38,3 +39,5 @@
 	spin_unlock(lock);
 	return 0;
 }
+#endif
+
--- diff/arch/i386/mach-visws/traps.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/mach-visws/traps.c	2004-05-27 18:34:15.000000000 +0100
@@ -8,7 +8,6 @@
 #include <linux/pci_ids.h>
 
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 #include <asm/arch_hooks.h>
 #include <asm/apic.h>
 #include "cobalt.h"
--- diff/arch/i386/mach-voyager/voyager_basic.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/mach-voyager/voyager_basic.c	2004-05-27 18:34:15.000000000 +0100
@@ -24,7 +24,6 @@
 #include <linux/reboot.h>
 #include <linux/sysrq.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 #include <asm/voyager.h>
 #include <asm/vic.h>
 #include <linux/pm.h>
--- diff/arch/i386/mach-voyager/voyager_smp.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/i386/mach-voyager/voyager_smp.c	2004-05-27 18:34:15.000000000 +0100
@@ -24,7 +24,6 @@
 #include <asm/desc.h>
 #include <asm/voyager.h>
 #include <asm/vic.h>
-#include <asm/pgalloc.h>
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
--- diff/arch/i386/mach-voyager/voyager_thread.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/mach-voyager/voyager_thread.c	2004-05-27 18:34:15.000000000 +0100
@@ -28,7 +28,6 @@
 #include <asm/desc.h>
 #include <asm/voyager.h>
 #include <asm/vic.h>
-#include <asm/pgalloc.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
 
--- diff/arch/i386/mm/extable.c	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/mm/extable.c	2004-05-27 18:34:15.000000000 +0100
@@ -5,6 +5,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+
 #include <asm/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
@@ -34,3 +35,15 @@
 
 	return 0;
 }
+
+int check_exception(struct pt_regs *regs)
+{
+	const struct exception_table_entry *fixup;
+
+	fixup = search_exception_tables(regs->eip);
+	if (fixup) {
+		return 1;
+	}
+
+	return 0;
+}
--- diff/arch/i386/mm/fault.c	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/mm/fault.c	2004-05-27 18:34:15.000000000 +0100
@@ -24,7 +24,6 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/hardirq.h>
 #include <asm/desc.h>
 
@@ -262,7 +261,26 @@
 	if (in_atomic() || !mm)
 		goto bad_area_nosemaphore;
 
-	down_read(&mm->mmap_sem);
+	/* When running in the kernel we expect faults to occur only to
+	 * addresses in user space.  All other faults represent errors in the
+	 * kernel and should generate an OOPS.  Unfortunatly, in the case of an
+	 * erroneous fault occuring in a code path which already holds mmap_sem
+	 * we will deadlock attempting to validate the fault against the
+	 * address space.  Luckily the kernel only validly references user
+	 * space from well defined areas of code, which are listed in the
+	 * exceptions table.
+	 *
+	 * As the vast majority of faults will be valid we will only perform
+	 * the source reference check when there is a possibilty of a deadlock.
+	 * Attempt to lock the address space, if we cannot we then validate the
+	 * source.  If this is invalid we can skip the address space check,
+	 * thus avoiding the deadlock.
+	 */
+	if (!down_read_trylock(&mm->mmap_sem)) {
+		if ((error_code & 4) == 0 && !check_exception(regs))
+			goto bad_area_nosemaphore;
+		down_read(&mm->mmap_sem);
+	}
 
 	vma = find_vma(mm, address);
 	if (!vma)
@@ -403,6 +421,12 @@
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
+#ifdef CONFIG_KGDB
+        if (!user_mode(regs)){
+                kgdb_handle_exception(14,SIGBUS, error_code, regs);
+                return;
+        }
+#endif
 
 	bust_spinlocks(1);
 
--- diff/arch/i386/mm/hugetlbpage.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/i386/mm/hugetlbpage.c	2004-05-27 18:34:15.000000000 +0100
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/sysctl.h>
 #include <asm/mman.h>
-#include <asm/pgalloc.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
--- diff/arch/i386/mm/init.c	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/mm/init.c	2004-05-27 18:34:15.000000000 +0100
@@ -32,7 +32,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/dma.h>
 #include <asm/fixmap.h>
 #include <asm/e820.h>
@@ -328,9 +327,30 @@
 #endif
 }
 
+#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND)
+/*
+ * Swap suspend & friends need this for resume because things like the intel-agp
+ * driver might have split up a kernel 4MB mapping.
+ */
+char __nosavedata swsusp_pg_dir[PAGE_SIZE]
+	__attribute__ ((aligned (PAGE_SIZE)));
+
+static inline void save_pg_dir(void)
+{
+	memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
+}
+#else
+static inline void save_pg_dir(void)
+{
+}
+#endif
+
 void zap_low_mappings (void)
 {
 	int i;
+
+	save_pg_dir();
+
 	/*
 	 * Zap initial low-memory mappings.
 	 *
--- diff/arch/i386/mm/ioremap.c	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/mm/ioremap.c	2004-05-27 18:34:15.000000000 +0100
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 #include <asm/fixmap.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
--- diff/arch/i386/pci/acpi.c	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/pci/acpi.c	2004-05-27 18:34:15.000000000 +0100
@@ -1,6 +1,8 @@
 #include <linux/pci.h>
 #include <linux/acpi.h>
 #include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/hw_irq.h>
 #include "pci.h"
 
 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
@@ -15,18 +17,31 @@
 
 static int __init pci_acpi_init(void)
 {
+	struct pci_dev *dev = NULL;
+
 	if (pcibios_scanned)
 		return 0;
 
-	if (!acpi_noirq) {
-		if (!acpi_pci_irq_init()) {
-			printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-			pcibios_scanned++;
-			pcibios_enable_irq = acpi_pci_irq_enable;
-		} else
-			printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
+	if (acpi_noirq)
+		return 0;
 
-	}
+	printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+	acpi_irq_penalty_init();
+	pcibios_scanned++;
+	pcibios_enable_irq = acpi_pci_irq_enable;
+
+	/*
+	 * PCI IRQ routing is set up by pci_enable_device(), but we
+	 * also do it here in case there are still broken drivers that
+	 * don't use pci_enable_device().
+	 */
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+		acpi_pci_irq_enable(dev);
+
+#ifdef CONFIG_X86_IO_APIC
+	if (acpi_ioapic)
+		print_IO_APIC();
+#endif
 
 	return 0;
 }
--- diff/arch/i386/power/pmdisk.S	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/power/pmdisk.S	2004-05-27 18:34:15.000000000 +0100
@@ -21,7 +21,7 @@
 	jmp .L1449
 	.p2align 4,,7
 .L1450:
-	movl $swapper_pg_dir-__PAGE_OFFSET,%ecx
+	movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx
 	movl %ecx,%cr3
 
 	movl	pm_pagedir_nosave,%ebx
--- diff/arch/i386/power/swsusp.S	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/power/swsusp.S	2004-05-27 18:34:15.000000000 +0100
@@ -36,7 +36,7 @@
 	jmp .L1449
 	.p2align 4,,7
 .L1450:
-	movl $swapper_pg_dir-__PAGE_OFFSET,%ecx
+	movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx
 	movl %ecx,%cr3
 
 	call do_magic_resume_1
--- diff/arch/ia64/Kconfig	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/ia64/Kconfig	2004-05-27 18:34:15.000000000 +0100
@@ -201,6 +201,184 @@
 	  or have huge holes in the physical address space for other reasons.
 	  See <file:Documentation/vm/numa> for more.
 
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb/kgdb.txt file.
+
+config	KGDB_EARLY
+	bool
+	depends on KGDB
+	default n
+	prompt "KGDB Early"
+	help
+	  Kgdb debugging in kernel can start shortly before/after setup_arch routine exits.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_IOMEM
+	hex "hex I/O port IOMEM address"
+	depends on KGDB
+	default	0xc0000000ff5e0000
+	help
+	  Some systems use IOMEM address for the port.  This value is from
+	  the rx2600 chassis console port.
+
+config KGDB_IOMEM_REG_SHIFT
+	hex "hex I/O port IOMEM reg shift"
+	depends on KGDB
+	default 0x0
+	help
+	  This is the memory shift for IOMEM.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 59
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub. This value
+	  is the rx2600 chassis's console port.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
 config IA64_CYCLONE
 	bool "Support Cyclone(EXA) Time Source"
 	help
@@ -445,6 +623,19 @@
 	  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
 	  unless you really know what this hack does.
 
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
+
 config DEBUG_SLAB
 	bool "Debug memory allocations"
 	depends on DEBUG_KERNEL
@@ -494,6 +685,13 @@
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
 
+config LOCKMETER
+       bool "Kernel lock metering"
+       depends on SMP
+       help
+         Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+         but allows you to see various statistics using the lockstat command.
+
 config SYSVIPC_COMPAT
 	bool
 	depends on COMPAT && SYSVIPC
--- diff/arch/ia64/kernel/Makefile	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/ia64/kernel/Makefile	2004-05-27 18:34:15.000000000 +0100
@@ -17,6 +17,7 @@
 obj-$(CONFIG_SMP)		+= smp.o smpboot.o
 obj-$(CONFIG_PERFMON)		+= perfmon_default_smpl.o
 obj-$(CONFIG_IA64_CYCLONE)	+= cyclone.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 
 # The gate DSO image is built using a special linker script.
 targets += gate.so gate-syms.o
--- diff/arch/ia64/kernel/acpi.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/ia64/kernel/acpi.c	2004-05-27 18:34:15.000000000 +0100
@@ -521,9 +521,14 @@
 #endif /* CONFIG_ACPI_NUMA */
 
 unsigned int
-acpi_register_gsi (u32 gsi, int polarity, int trigger)
+acpi_register_gsi (u32 gsi, int edge_level, int active_high_low)
 {
-	return acpi_register_irq(gsi, polarity, trigger);
+	if (has_8259 && gsi < 16)
+		return isa_irq_to_vector(gsi);
+
+	return iosapic_register_intr(gsi,
+			(active_high_low == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+			(edge_level == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
 }
 EXPORT_SYMBOL(acpi_register_gsi);
 
@@ -548,7 +553,7 @@
 	if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES)
 		acpi_legacy_devices = 1;
 
-	acpi_register_gsi(fadt->sci_int, ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE);
+	acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
 	return 0;
 }
 
@@ -662,16 +667,4 @@
 	return 0;
 }
 
-int
-acpi_register_irq (u32 gsi, u32 polarity, u32 trigger)
-{
-	if (has_8259 && gsi < 16)
-		return isa_irq_to_vector(gsi);
-
-	return iosapic_register_intr(gsi,
-			(polarity == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
-			(trigger == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
-}
-EXPORT_SYMBOL(acpi_register_irq);
-
 #endif /* CONFIG_ACPI_BOOT */
--- diff/arch/ia64/kernel/init_task.c	2004-05-19 22:11:03.000000000 +0100
+++ source/arch/ia64/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/ia64/kernel/iosapic.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/ia64/kernel/iosapic.c	2004-05-27 18:34:15.000000000 +0100
@@ -483,7 +483,7 @@
 
 	index = find_iosapic(gsi);
 	if (index < 0) {
-		printk(KERN_WARNING "%s: No IOSAPIC for GSI 0x%x\n", __FUNCTION__, gsi);
+		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
 		return;
 	}
 
@@ -512,6 +512,42 @@
 	}
 }
 
+static unsigned int
+get_target_cpu (void)
+{
+#ifdef CONFIG_SMP
+	static int cpu = -1;
+
+	/*
+	 * If the platform supports redirection via XTP, let it
+	 * distribute interrupts.
+	 */
+	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
+		return hard_smp_processor_id();
+
+	/*
+	 * Some interrupts (ACPI SCI, for instance) are registered
+	 * before the BSP is marked as online.
+	 */
+	if (!cpu_online(smp_processor_id()))
+		return hard_smp_processor_id();
+
+	/*
+	 * Otherwise, round-robin interrupt vectors across all the
+	 * processors.  (It'd be nice if we could be smarter in the
+	 * case of NUMA.)
+	 */
+	do {
+		if (++cpu >= NR_CPUS)
+			cpu = 0;
+	} while (!cpu_online(cpu));
+
+	return cpu_physical_id(cpu);
+#else
+	return hard_smp_processor_id();
+#endif
+}
+
 /*
  * ACPI can describe IOSAPIC interrupts via static tables and namespace
  * methods.  This provides an interface to register those interrupts and
@@ -522,21 +558,35 @@
 		       unsigned long polarity, unsigned long trigger)
 {
 	int vector;
-	unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
-
-	vector = gsi_to_vector(gsi);
-	if (vector < 0)
-		vector = assign_irq_vector(AUTO_ASSIGN);
+	unsigned int dest;
+	unsigned long flags;
 
-	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
-		      polarity, trigger);
+	/*
+	 * If this GSI has already been registered (i.e., it's a
+	 * shared interrupt, or we lost a race to register it),
+	 * don't touch the RTE.
+	 */
+	spin_lock_irqsave(&iosapic_lock, flags);
+	{
+		vector = gsi_to_vector(gsi);
+		if (vector > 0) {
+			spin_unlock_irqrestore(&iosapic_lock, flags);
+			return vector;
+		}
 
-	printk(KERN_INFO "GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-	       gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-	       (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
+		vector = assign_irq_vector(AUTO_ASSIGN);
+		dest = get_target_cpu();
+		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
+			polarity, trigger);
+	}
+	spin_unlock_irqrestore(&iosapic_lock, flags);
+
+	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
+	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+	       cpu_logical_id(dest), dest, vector);
 
-	/* program the IOSAPIC routing table */
-	set_rte(vector, dest, 0);
+	set_rte(vector, dest, 1);
 	return vector;
 }
 
@@ -549,8 +599,9 @@
 				int iosapic_vector, u16 eid, u16 id,
 				unsigned long polarity, unsigned long trigger)
 {
+	static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
 	unsigned char delivery;
-	int vector;
+	int vector, mask = 0;
 	unsigned int dest = ((id << 8) | eid) & 0xffff;
 
 	switch (int_type) {
@@ -570,21 +621,22 @@
 	      case ACPI_INTERRUPT_CPEI:
 		vector = IA64_CPE_VECTOR;
 		delivery = IOSAPIC_LOWEST_PRIORITY;
+		mask = 1;
 		break;
 	      default:
-		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type\n");
+		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
 		return -1;
 	}
 
-	register_intr(gsi, vector, delivery, polarity,
-		      trigger);
+	register_intr(gsi, vector, delivery, polarity, trigger);
 
-	printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-	       int_type, gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-	       (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
+	printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
+	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
+	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+	       cpu_logical_id(dest), dest, vector);
 
-	/* program the IOSAPIC routing table */
-	set_rte(vector, dest, 0);
+	set_rte(vector, dest, mask);
 	return vector;
 }
 
@@ -599,18 +651,18 @@
 			  unsigned long trigger)
 {
 	int vector;
-	unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
+	unsigned int dest = hard_smp_processor_id();
 
 	vector = isa_irq_to_vector(isa_irq);
 
 	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
 
-	DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
-	    isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low",
-	    trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector);
+	DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
+	    isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
+	    polarity == IOSAPIC_POL_HIGH ? "high" : "low",
+	    cpu_logical_id(dest), dest, vector);
 
-	/* program the IOSAPIC routing table */
-	set_rte(vector, dest, 0);
+	set_rte(vector, dest, 1);
 }
 
 void __init
@@ -665,104 +717,3 @@
 			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
 	}
 }
-
-void
-iosapic_enable_intr (unsigned int vector)
-{
-	unsigned int dest;
-	irq_desc_t *desc;
-
-	/*
-	 * In the case of a shared interrupt, do not re-route the vector, and
-	 * especially do not mask a running interrupt (startup will not get
-	 * called for a shared interrupt).
-	 */
-	desc = irq_descp(vector);
-	if (desc->action)
-		return;
-
-#ifdef CONFIG_SMP
-	/*
-	 * For platforms that do not support interrupt redirect via the XTP interface, we
-	 * can round-robin the PCI device interrupts to the processors
-	 */
-	if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
-		static int cpu_index = -1;
-
-		do
-			if (++cpu_index >= NR_CPUS)
-				cpu_index = 0;
-		while (!cpu_online(cpu_index));
-
-		dest = cpu_physical_id(cpu_index) & 0xffff;
-	} else {
-		/*
-		 * Direct the interrupt vector to the current cpu, platform redirection
-		 * will distribute them.
-		 */
-		dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
-	}
-#else
-	/* direct the interrupt vector to the running cpu id */
-	dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
-#endif
-	set_rte(vector, dest, 1);
-
-	printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n",
-	       vector, dest);
-}
-
-#ifdef CONFIG_ACPI_PCI
-
-void __init
-iosapic_parse_prt (void)
-{
-	struct acpi_prt_entry *entry;
-	struct list_head *node;
-	unsigned int gsi;
-	int vector;
-	char pci_id[16];
-	struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
-	irq_desc_t *idesc;
-
-	list_for_each(node, &acpi_prt.entries) {
-		entry = list_entry(node, struct acpi_prt_entry, node);
-
-		/* We're only interested in static (non-link) entries.  */
-		if (entry->link.handle)
-			continue;
-
-		gsi = entry->link.index;
-
-		vector = gsi_to_vector(gsi);
-		if (vector < 0) {
-			if (find_iosapic(gsi) < 0)
-				continue;
-
-			/* allocate a vector for this interrupt line */
-			if (pcat_compat && (gsi < 16))
-				vector = isa_irq_to_vector(gsi);
-			else
-				/* new GSI; allocate a vector for it */
-				vector = assign_irq_vector(AUTO_ASSIGN);
-
-			register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
-				      IOSAPIC_LEVEL);
-		}
-		entry->irq = vector;
-		snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
-			 entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin);
-
-		/*
-		 * If vector was previously initialized to a different
-		 * handler, re-initialize.
-		 */
-		idesc = irq_descp(vector);
-		if (idesc->handler != irq_type)
-			register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
-				      IOSAPIC_LEVEL);
-
-	}
-}
-
-#endif /* CONFIG_ACPI */
--- diff/arch/ia64/kernel/irq.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/ia64/kernel/irq.c	2004-05-27 18:34:15.000000000 +0100
@@ -534,6 +534,11 @@
 		desc->handler->end(irq);
 		spin_unlock(&desc->lock);
 	}
+
+#ifdef	CONFIG_KGDB
+	kgdb_process_breakpoint();
+#endif
+
 	return 1;
 }
 
--- diff/arch/ia64/kernel/ivt.S	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/ia64/kernel/ivt.S	2004-05-27 18:34:15.000000000 +0100
@@ -68,6 +68,13 @@
 # define DBG_FAULT(i)
 #endif
 
+#ifdef	CONFIG_KGDB
+#define	KGDB_ENABLE_PSR_DB mov r31=psr;; movl r30=IA64_PSR_DB;; or r31=r31,r30;; \
+		mov psr.l=r31;; srlz.i;;
+#else
+#define	KGDB_ENABLE_PSR_DB
+#endif
+
 #define MINSTATE_VIRT	/* needed by minstate.h */
 #include "minstate.h"
 
@@ -473,6 +480,7 @@
 	movl r14=ia64_leave_kernel
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	mov rp=r14
 	;;
 	adds out2=16,r12			// out2 = pointer to pt_regs
@@ -733,6 +741,8 @@
 	;;
 	srlz.i					// guarantee that interruption collection is on
 	;;
+	KGDB_ENABLE_PSR_DB
+	;;
 (p15)	ssm psr.i				// restore psr.i
 	;;
 	mov r3=NR_syscalls - 1
@@ -774,6 +784,7 @@
 	srlz.i			// ensure everybody knows psr.ic is back on
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	;;
 	alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group
 	mov out0=cr.ivr		// pass cr.ivr as first arg
@@ -1001,6 +1012,7 @@
 	movl r15=ia64_leave_kernel
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	mov rp=r15
 	;;
 	br.call.sptk.many b6=ia64_bad_break	// avoid WAW on CFM and ignore return addr
@@ -1034,6 +1046,7 @@
 	adds r3=8,r2				// set up second base pointer
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	movl r14=ia64_leave_kernel
 	;;
 	mov rp=r14
@@ -1076,6 +1089,7 @@
 	adds r3=8,r2				// set up second base pointer for SAVE_REST
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	movl r14=ia64_leave_kernel
 	;;
 	mov rp=r14
--- diff/arch/ia64/kernel/machvec.c	2004-05-27 13:41:12.000000000 +0100
+++ source/arch/ia64/kernel/machvec.c	2004-05-27 18:34:15.000000000 +0100
@@ -62,6 +62,12 @@
 EXPORT_SYMBOL(machvec_timer_interrupt);
 
 void
+machvec_tlb_migrate_finish (struct mm_struct *mm)
+{
+}
+EXPORT_SYMBOL(machvec_tlb_migrate_finish);
+
+void
 machvec_dma_sync_single (struct device *hwdev, dma_addr_t dma_handle, size_t size, int dir)
 {
 	mb();
--- diff/arch/ia64/kernel/process.c	2004-05-27 13:41:13.000000000 +0100
+++ source/arch/ia64/kernel/process.c	2004-05-27 18:34:15.000000000 +0100
@@ -407,6 +407,9 @@
 	 */
 	child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
 				 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
+#ifdef	CONFIG_KGDB
+	child_ptregs->cr_ipsr |= IA64_PSR_DB;
+#endif
 
 	/*
 	 * NOTE: The calling convention considers all floating point
@@ -639,6 +642,9 @@
 	regs.pt.r11 = (unsigned long) arg;	/* 2nd argument */
 	/* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read.  */
 	regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
+#ifdef	CONFIG_KGDB
+	regs.pt.cr_ipsr |= IA64_PSR_DB;
+#endif
 	regs.pt.cr_ifs = 1UL << 63;		/* mark as valid, empty frame */
 	regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR);
 	regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET;
--- diff/arch/ia64/kernel/setup.c	2004-05-27 13:41:13.000000000 +0100
+++ source/arch/ia64/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -50,6 +50,7 @@
 #include <asm/smp.h>
 #include <asm/system.h>
 #include <asm/unistd.h>
+#include <asm/kgdb.h>
 
 #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
 # error "struct cpuinfo_ia64 too big!"
@@ -88,10 +89,6 @@
 unsigned long ia64_max_iommu_merge_mask = ~0UL;
 EXPORT_SYMBOL(ia64_max_iommu_merge_mask);
 
-#define COMMAND_LINE_SIZE	512
-
-char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */
-
 /*
  * We use a special marker for the end of memory and it uses the extra (+1) slot
  */
@@ -359,11 +356,36 @@
 		conswitchp = &vga_con;
 # endif
 #endif
+#ifndef	CONFIG_IA64_HP_SIM
+#ifdef	CONFIG_KGDB
+	{
+		unsigned long total_ibr, total_dbr;
+		long status;
+		int dbr;
+
+		status = ia64_pal_debug_info(&total_ibr, &total_dbr);
+
+		if (!status) {
+			printk(KERN_INFO "kgdb has DBR = %d IBR = %d\n",
+				(int) total_dbr, (int) total_ibr);
+
+			for (dbr = 0; dbr < total_dbr; dbr++)
+				ia64_set_dbr((dbr << 1) + 1, 0);
+			for (dbr = 0; dbr < total_ibr; dbr++)
+				ia64_set_ibr((dbr << 1) + 1, 0);
+		}
+	}
+#endif
+#endif
+
 
 	/* enable IA-64 Machine Check Abort Handling */
 	ia64_mca_init();
 
 	platform_setup(cmdline_p);
+#ifdef	CONFIG_KGDB_EARLY
+	kgdb_serial_init();
+#endif
 	paging_init();
 }
 
--- diff/arch/ia64/kernel/smp.c	2004-05-27 13:41:13.000000000 +0100
+++ source/arch/ia64/kernel/smp.c	2004-05-27 18:34:15.000000000 +0100
@@ -47,6 +47,7 @@
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
 #include <asm/mca.h>
+#include <asm/kgdb.h>
 
 /*
  * Structure and data for smp_call_function(). This is designed to minimise static memory
@@ -66,6 +67,9 @@
 
 #define IPI_CALL_FUNC		0
 #define IPI_CPU_STOP		1
+#ifdef	CONFIG_KGDB
+#define	IPI_KGDB_INTERRUPT	2
+#endif
 
 /* This needs to be cacheline aligned because it is written to by *other* CPUs.  */
 static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
@@ -156,6 +160,12 @@
 				stop_this_cpu();
 				break;
 
+#ifdef	CONFIG_KGDB
+			      case IPI_KGDB_INTERRUPT:
+				(void) in_kgdb(regs, NULL);
+				break;
+#endif
+
 			      default:
 				printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
 				break;
@@ -361,6 +371,14 @@
 }
 EXPORT_SYMBOL(smp_call_function);
 
+#ifdef	CONFIG_KGDB
+void
+smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(IPI_KGDB_INTERRUPT);
+}
+#endif
+
 /*
  * this function calls the 'stop' function on all other CPUs in the system.
  */
--- diff/arch/ia64/kernel/traps.c	2004-05-27 13:41:13.000000000 +0100
+++ source/arch/ia64/kernel/traps.c	2004-05-27 18:34:15.000000000 +0100
@@ -35,6 +35,19 @@
 		fpswa_interface = __va(ia64_boot_param->fpswa);
 }
 
+#ifdef	CONFIG_KGDB
+extern int kgdb_handle_exception(int, int, int, struct pt_regs *);
+#define	CHK_REMOTE_DEBUG(trapnr, signr, error_code, regs, after)		\
+	{									\
+		if (!user_mode(regs)) {						\
+			kgdb_handle_exception(trapnr, signr, error_code, regs);	\
+			after;							\
+		}								\
+	}
+#else
+#define	CHK_REMOTE_DEBUG(trapnr, signr, error_code, regs, after)
+#endif
+
 /*
  * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock
  * is acquired through the console unblank code)
@@ -85,6 +98,8 @@
 		bust_spinlocks(1);
 	}
 
+	CHK_REMOTE_DEBUG(-1, SIGTRAP, err, regs,)
+
 	if (++die.lock_owner_depth < 3) {
 		printk("%s[%d]: %s %ld [%d]\n",
 			current->comm, current->pid, str, err, ++die_counter);
@@ -117,9 +132,13 @@
 	siginfo.si_flags = 0;		/* clear __ISR_VALID */
 	siginfo.si_isr = 0;
 
+
+
 	switch (break_num) {
 	      case 0: /* unknown error (used by GCC for __builtin_abort()) */
+#ifndef	CONFIG_KGDB
 		die_if_kernel("bugcheck!", regs, break_num);
+#endif
 		sig = SIGILL; code = ILL_ILLOPC;
 		break;
 
@@ -172,8 +191,10 @@
 		break;
 
 	      default:
+#ifndef	CONFIG_KGDB
 		if (break_num < 0x40000 || break_num > 0x100000)
 			die_if_kernel("Bad break", regs, break_num);
+#endif
 
 		if (break_num < 0x80000) {
 			sig = SIGILL; code = __ILL_BREAK;
@@ -181,6 +202,13 @@
 			sig = SIGTRAP; code = TRAP_BRKPT;
 		}
 	}
+#ifdef	CONFIG_KGDB
+	/*
+	 * We don't want to trap simulator system calls.
+	 */
+	if (break_num != 0x80001)
+		CHK_REMOTE_DEBUG(11, sig, break_num, regs, return)
+#endif
 	siginfo.si_signo = sig;
 	siginfo.si_errno = 0;
 	siginfo.si_code = code;
@@ -488,8 +516,9 @@
 		break;
 
 	      case 29: /* Debug */
-	      case 35: /* Taken Branch Trap */
 	      case 36: /* Single Step Trap */
+		CHK_REMOTE_DEBUG(vector, SIGTRAP, isr, regs, return)
+	      case 35: /* Taken Branch Trap */
 		if (fsys_mode(current, regs)) {
 			extern char __kernel_syscall_via_break[];
 			/*
@@ -603,6 +632,7 @@
 		sprintf(buf, "Fault %lu", vector);
 		break;
 	}
+	CHK_REMOTE_DEBUG(vector, SIGTRAP, isr, regs,)
 	die_if_kernel(buf, regs, error);
 	force_sig(SIGILL, current);
 }
--- diff/arch/ia64/kernel/unwind.c	2004-05-27 13:41:13.000000000 +0100
+++ source/arch/ia64/kernel/unwind.c	2004-05-27 18:34:15.000000000 +0100
@@ -75,10 +75,69 @@
 # define STAT(x...)
 #endif
 
+
+#ifdef	CONFIG_KGDB_EARLY
+#define	KGDB_EARLY_SIZE	100
+static struct unw_reg_state __initdata kgdb_reg_state[KGDB_EARLY_SIZE];
+static struct unw_labeled_state __initdata kgdb_labeled_state[KGDB_EARLY_SIZE];
+void __initdata *kgdb_reg_state_free, __initdata *kgdb_labeled_state_free;
+
+static void __init
+kgdb_malloc_init(void)
+{
+	int i;
+
+	kgdb_reg_state_free = kgdb_reg_state;
+	for (i = 1; i < KGDB_EARLY_SIZE; i++) {
+		*((unsigned long *) &kgdb_reg_state[i]) = (unsigned long) kgdb_reg_state_free;
+		kgdb_reg_state_free = &kgdb_reg_state[i];
+	}
+
+	kgdb_labeled_state_free = kgdb_labeled_state;
+	for (i = 1; i < KGDB_EARLY_SIZE; i++) {
+		*((unsigned long *) &kgdb_labeled_state[i]) =
+			(unsigned long) kgdb_labeled_state_free;
+		kgdb_labeled_state_free = &kgdb_labeled_state[i];
+	}
+
+}
+
+static void * __init
+kgdb_malloc(void **mem)
+{
+	void *p;
+
+	p = *mem;
+	*mem = *((void **) p);
+	return p;
+}
+
+static void __init
+kgdb_free(void **mem, void *p)
+{
+	*((void **)p) = *mem;
+	*mem = p;
+}
+
+#define alloc_reg_state()	(!malloc_sizes[0].cs_cachep ? 		\
+		kgdb_malloc(&kgdb_reg_state_free) : 			\
+		kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC))
+#define free_reg_state(usr)	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_free(&kgdb_reg_state_free, usr) :			\
+		kfree(usr))
+#define alloc_labeled_state()	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_malloc(&kgdb_labeled_state_free) :			\
+		kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC))
+#define free_labeled_state(usr)	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_free(&kgdb_labeled_state_free, usr) :		\
+		kfree(usr))
+
+#else
 #define alloc_reg_state()	kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC)
 #define free_reg_state(usr)	kfree(usr)
 #define alloc_labeled_state()	kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)
 #define free_labeled_state(usr)	kfree(usr)
+#endif
 
 typedef unsigned long unw_word;
 typedef unsigned char unw_hash_index_t;
@@ -2262,6 +2321,10 @@
 
 	init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp,
 			  __start_unwind, __end_unwind);
+
+#ifdef	CONFIG_KGDB_EARLY
+	kgdb_malloc_init();
+#endif
 }
 
 /*
--- diff/arch/ia64/lib/Makefile	2004-05-19 22:11:04.000000000 +0100
+++ source/arch/ia64/lib/Makefile	2004-05-27 18:34:15.000000000 +0100
@@ -16,6 +16,7 @@
 lib-$(CONFIG_PERFMON)	+= carta_random.o
 lib-$(CONFIG_MD_RAID5)	+= xor.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB)	+= kgdb_serial.o
 
 AFLAGS___divdi3.o	=
 AFLAGS___udivdi3.o	= -DUNSIGNED
--- diff/arch/ia64/lib/dec_and_lock.c	2004-05-19 22:11:04.000000000 +0100
+++ source/arch/ia64/lib/dec_and_lock.c	2004-05-27 18:34:15.000000000 +0100
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
+#ifndef CONFIG_LOCKMETER
 /*
  * Decrement REFCOUNT and if the count reaches zero, acquire the spinlock.  Both of these
  * operations have to be done atomically, so that the count doesn't drop to zero without
@@ -40,3 +41,4 @@
 }
 
 EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
--- diff/arch/ia64/mm/fault.c	2004-05-19 22:11:04.000000000 +0100
+++ source/arch/ia64/mm/fault.c	2004-05-27 18:34:15.000000000 +0100
@@ -15,6 +15,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
+#include <asm/kgdb.h>
 
 extern void die (char *, struct pt_regs *, long);
 
@@ -232,6 +233,11 @@
 	 */
 	bust_spinlocks(1);
 
+#ifdef	CONFIG_KGDB
+	kgdb_handle_exception(5, SIGBUS, isr, regs);
+	return;
+#endif
+
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference (address %016lx)\n", address);
 	else
--- diff/arch/ia64/pci/pci.c	2004-05-19 22:11:04.000000000 +0100
+++ source/arch/ia64/pci/pci.c	2004-05-27 18:34:15.000000000 +0100
@@ -134,10 +134,18 @@
 static int __init
 pci_acpi_init (void)
 {
-	if (!acpi_pci_irq_init())
-		printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-	else
-		printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
+	struct pci_dev *dev = NULL;
+
+	printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+
+	/*
+	 * PCI IRQ routing is set up by pci_enable_device(), but we
+	 * also do it here in case there are still broken drivers that
+	 * don't use pci_enable_device().
+	 */
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+		acpi_pci_irq_enable(dev);
+
 	return 0;
 }
 
--- diff/arch/ia64/sn/kernel/sn2/sn2_smp.c	2004-05-19 22:11:05.000000000 +0100
+++ source/arch/ia64/sn/kernel/sn2/sn2_smp.c	2004-05-27 18:34:15.000000000 +0100
@@ -27,6 +27,7 @@
 #include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/smp.h>
+#include <asm/tlb.h>
 #include <asm/numa.h>
 #include <asm/bitops.h>
 #include <asm/hw_irq.h>
@@ -60,6 +61,13 @@
 }
 
 
+void
+sn_tlb_migrate_finish(struct mm_struct *mm)
+{
+	if (mm == current->mm)
+		flush_tlb_mm(mm);
+}
+
 
 /**
  * sn2_global_tlb_purge - globally purge translation cache of virtual address range
@@ -114,6 +122,13 @@
 		return;
 	}
 
+	if (atomic_read(&mm->mm_users) == 1) {
+		flush_tlb_mm(mm);
+		preempt_enable();
+		return;
+	}
+
+
 	nix = 0;
 	for (cnode=find_first_bit(&nodes_flushed, NR_NODES); cnode < NR_NODES; 
 			cnode=find_next_bit(&nodes_flushed, NR_NODES, ++cnode))
--- diff/arch/m68k/kernel/process.c	2004-05-27 13:41:14.000000000 +0100
+++ source/arch/m68k/kernel/process.c	2004-05-27 18:34:15.000000000 +0100
@@ -26,6 +26,7 @@
 #include <linux/a.out.h>
 #include <linux/reboot.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
--- diff/arch/m68k/kernel/setup.c	2004-05-27 13:41:14.000000000 +0100
+++ source/arch/m68k/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -62,7 +62,6 @@
 static struct mem_info m68k_ramdisk;
 
 static char m68k_command_line[CL_SIZE];
-char saved_command_line[CL_SIZE];
 
 char m68k_debug_device[6] = "";
 
--- diff/arch/m68k/q40/config.c	2004-05-27 13:41:15.000000000 +0100
+++ source/arch/m68k/q40/config.c	2004-05-27 18:34:15.000000000 +0100
@@ -64,7 +64,6 @@
 
 extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
 
-extern char *saved_command_line;
 extern char m68k_debug_device[];
 static void q40_mem_console_write(struct console *co, const char *b,
 				    unsigned int count);
--- diff/arch/m68knommu/kernel/init_task.c	2004-05-19 22:11:07.000000000 +0100
+++ source/arch/m68knommu/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/m68knommu/kernel/setup.c	2004-05-19 22:11:07.000000000 +0100
+++ source/arch/m68knommu/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -31,6 +31,7 @@
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -44,8 +45,7 @@
 unsigned long memory_start;
 unsigned long memory_end;
 
-char command_line[512];
-char saved_command_line[512];
+char command_line[COMMAND_LINE_SIZE];
 
 /* setup some dummy routines */
 static void dummy_waitbut(void)
--- diff/arch/mips/kernel/init_task.c	2004-05-19 22:11:09.000000000 +0100
+++ source/arch/mips/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -3,6 +3,7 @@
 #include <linux/sched.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/thread_info.h>
 #include <asm/uaccess.h>
--- diff/arch/mips/kernel/setup.c	2004-05-19 22:11:10.000000000 +0100
+++ source/arch/mips/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -71,7 +71,6 @@
 struct boot_mem_map boot_mem_map;
 
 static char command_line[CL_SIZE];
-       char saved_command_line[CL_SIZE];
        char arcs_cmdline[CL_SIZE]=CONFIG_CMDLINE;
 
 /*
--- diff/arch/parisc/kernel/init_task.c	2004-05-27 13:41:15.000000000 +0100
+++ source/arch/parisc/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/parisc/kernel/setup.c	2004-05-27 13:41:15.000000000 +0100
+++ source/arch/parisc/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -45,8 +45,6 @@
 #include <asm/pdc_chassis.h>
 #include <asm/io.h>
 
-#define COMMAND_LINE_SIZE 1024
-char	saved_command_line[COMMAND_LINE_SIZE];
 char	command_line[COMMAND_LINE_SIZE];
 
 /* Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} */
--- diff/arch/ppc/Kconfig	2004-05-27 13:41:15.000000000 +0100
+++ source/arch/ppc/Kconfig	2004-05-27 18:34:15.000000000 +0100
@@ -1227,6 +1227,19 @@
 	  debug the kernel.
 	  If you don't debug the kernel, you can say N.
 
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
+
 config BOOTX_TEXT
 	bool "Support for early boot text console (BootX or OpenFirmware only)"
 	depends PPC_OF
--- diff/arch/ppc/boot/Makefile	2004-05-19 22:11:13.000000000 +0100
+++ source/arch/ppc/boot/Makefile	2004-05-27 18:34:15.000000000 +0100
@@ -17,11 +17,11 @@
 
 bootdir-y			:= simple
 bootdir-$(CONFIG_PPC_OF)	+= openfirmware
-subdir-y			:= lib/ common/ images/
-subdir-$(CONFIG_PPC_OF)		+= of1275/
+subdir-y			:= lib common images
+subdir-$(CONFIG_PPC_OF)		+= of1275
 
 # for cleaning
-subdir-				+= simple/ openfirmware/
+subdir-				+= simple openfirmware
 
 host-progs := $(addprefix utils/, addnote mknote hack-coff mkprep mkbugboot mktree)
 
--- diff/arch/ppc/boot/openfirmware/Makefile	2004-05-19 22:11:14.000000000 +0100
+++ source/arch/ppc/boot/openfirmware/Makefile	2004-05-27 18:34:15.000000000 +0100
@@ -22,9 +22,10 @@
 images	:= $(boot)/images
 
 OBJCOPY_ARGS	:= -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
-COFF_LD_ARGS	:= -T $(boot)/ld.script -e _start -Ttext 0x00500000 -Bstatic
-CHRP_LD_ARGS	:= -T $(boot)/ld.script -e _start -Ttext 0x00800000
-NEWWORLD_LD_ARGS:= -T $(boot)/ld.script -e _start -Ttext 0x01000000
+COFF_LD_ARGS	:= -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x00500000 \
+			-Bstatic
+CHRP_LD_ARGS	:= -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x00800000
+NEWWORLD_LD_ARGS:= -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x01000000
 
 COMMONOBJS	:= start.o misc.o common.o
 COFFOBJS	:= coffcrt0.o $(COMMONOBJS) coffmain.o
@@ -92,11 +93,11 @@
       cmd_gencoffb = $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) $< $(LIBS) && \
                      $(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec)
 targets += coffboot
-$(obj)/coffboot: $(obj)/image.o $(COFFOBJS) $(LIBS) $(boot)/ld.script FORCE
+$(obj)/coffboot: $(obj)/image.o $(COFFOBJS) $(LIBS) $(srctree)/$(boot)/ld.script FORCE
 	$(call if_changed,gencoffb)
 targets += coffboot.initrd
 $(obj)/coffboot.initrd: $(obj)/image.initrd.o $(COFFOBJS) $(LIBS) \
-			$(boot)/ld.script FORCE
+			$(srctree)/$(boot)/ld.script FORCE
 	$(call if_changed,gencoffb)
 
 
@@ -118,20 +119,22 @@
 					 -R .comment $(del-ramdisk-sec)
 
 $(images)/vmlinux.elf-pmac: $(obj)/image.o $(NEWWORLDOBJS) $(LIBS) \
-			$(obj)/note $(boot)/ld.script
+			$(obj)/note $(srctree)/$(boot)/ld.script
 	$(call cmd,gen-elf-pmac)
 $(images)/vmlinux.initrd.elf-pmac: $(obj)/image.initrd.o $(NEWWORLDOBJS) \
-				   $(LIBS) $(obj)/note $(boot)/ld.script
+				   $(LIBS) $(obj)/note \
+				   $(srctree)/$(boot)/ld.script
 	$(call cmd,gen-elf-pmac)
 
 quiet_cmd_gen-chrp = CHRP    $@
       cmd_gen-chrp = $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) $< $(LIBS) && \
 			$(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec)
 
-$(images)/zImage.chrp: $(obj)/image.o $(CHRPOBJS) $(LIBS) $(boot)/ld.script
+$(images)/zImage.chrp: $(obj)/image.o $(CHRPOBJS) $(LIBS) \
+				   $(srctree)/$(boot)/ld.script
 	$(call cmd,gen-chrp)
 $(images)/zImage.initrd.chrp: $(obj)/image.initrd.o $(CHRPOBJS) $(LIBS) \
-			$(boot)/ld.script
+				   $(srctree)/$(boot)/ld.script
 	$(call cmd,gen-chrp)
 
 quiet_cmd_addnote = ADDNOTE $@
--- diff/arch/ppc/boot/simple/Makefile	2004-05-27 13:41:15.000000000 +0100
+++ source/arch/ppc/boot/simple/Makefile	2004-05-27 18:34:15.000000000 +0100
@@ -41,7 +41,7 @@
 # if present on 'classic' PPC.
 cacheflag-y	:= -DCLEAR_CACHES=""
 # This file will flush / disable the L2, and L3 if present.
-clear_L2_L3	:= $(srctree)/$(boot)/simple/clear.S
+clear_L2_L3	:= $(boot)/simple/clear.S
 
 #
 # See arch/ppc/kconfig and arch/ppc/platforms/Kconfig
--- diff/arch/ppc/kernel/process.c	2004-05-27 13:41:15.000000000 +0100
+++ source/arch/ppc/kernel/process.c	2004-05-27 18:34:15.000000000 +0100
@@ -35,6 +35,7 @@
 #include <linux/init_task.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/mqueue.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
--- diff/arch/ppc/kernel/setup.c	2004-05-27 13:41:15.000000000 +0100
+++ source/arch/ppc/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -54,7 +54,6 @@
 extern void power4_idle(void);
 
 extern boot_infos_t *boot_infos;
-char saved_command_line[COMMAND_LINE_SIZE];
 unsigned char aux_device_present;
 struct ide_machdep_calls ppc_ide_md;
 char *sysmap;
--- diff/arch/ppc/platforms/lopec_setup.c	2004-05-19 22:11:16.000000000 +0100
+++ source/arch/ppc/platforms/lopec_setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -33,7 +33,6 @@
 #include <asm/hw_irq.h>
 #include <asm/prep_nvram.h>
 
-extern char saved_command_line[];
 extern void lopec_find_bridges(void);
 
 /*
--- diff/arch/ppc/platforms/pmac_setup.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc/platforms/pmac_setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -103,8 +103,6 @@
 
 static int current_root_goodness = -1;
 
-extern char saved_command_line[];
-
 extern int pmac_newworld;
 
 #define DEFAULT_ROOT_DEVICE Root_SDA1	/* sda1 - slightly silly choice */
--- diff/arch/ppc/platforms/pplus.c	2004-05-19 22:11:16.000000000 +0100
+++ source/arch/ppc/platforms/pplus.c	2004-05-27 18:34:15.000000000 +0100
@@ -48,8 +48,6 @@
 
 TODC_ALLOC();
 
-extern char saved_command_line[];
-
 extern void pplus_setup_hose(void);
 extern void pplus_set_VIA_IDE_native(void);
 
--- diff/arch/ppc/platforms/prep_setup.c	2004-05-19 22:11:16.000000000 +0100
+++ source/arch/ppc/platforms/prep_setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -76,7 +76,6 @@
 extern void ibm_prep_init(void);
 
 extern void prep_find_bridges(void);
-extern char saved_command_line[];
 
 int _prep_type;
 
--- diff/arch/ppc64/Kconfig	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/Kconfig	2004-05-27 18:34:15.000000000 +0100
@@ -417,9 +417,29 @@
 	  debugging info resulting in a larger kernel image.
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
+
+config IRQSTACKS
+	bool "Use separate kernel stacks when processing interrupts"
+	help
+	  If you say Y here the kernel will use separate kernel stacks
+	  for handling hard and soft interrupts.  This can help avoid
+	  overflowing the process kernel stacks.
 	  
 endmenu
 
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
+
 config SPINLINE
 	bool "Inline spinlock code at each call site"
 	depends on SMP && !PPC_SPLPAR && !PPC_ISERIES
--- diff/arch/ppc64/kernel/head.S	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/kernel/head.S	2004-05-27 18:34:15.000000000 +0100
@@ -35,6 +35,7 @@
 #include <asm/offsets.h>
 #include <asm/bug.h>
 #include <asm/cputable.h>
+#include <asm/setup.h>
 
 #ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
@@ -1281,6 +1282,10 @@
 	SAVE_4GPRS(16, r1)
 	SAVE_8GPRS(24, r1)
 
+	/* Set the marker value "regshere" just before the reg values */
+	SET_REG_TO_CONST(r22, 0x7265677368657265)
+	std	r22,STACK_FRAME_OVERHEAD-16(r1)
+
 	/*
 	 * Clear the RESULT field
 	 */
@@ -2273,4 +2278,4 @@
  */
 	.globl	cmd_line
 cmd_line:
-	.space	512	/* COMMAND_LINE_SIZE */
+	.space	COMMAND_LINE_SIZE
--- diff/arch/ppc64/kernel/init_task.c	2004-05-19 22:11:18.000000000 +0100
+++ source/arch/ppc64/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 #include <asm/uaccess.h>
 
 static struct fs_struct init_fs = INIT_FS;
--- diff/arch/ppc64/kernel/ioctl32.c	2004-05-19 22:11:18.000000000 +0100
+++ source/arch/ppc64/kernel/ioctl32.c	2004-05-27 18:34:15.000000000 +0100
@@ -29,307 +29,6 @@
 #define CODE
 #include "compat_ioctl.c"
 
-struct ncp_ioctl_request_32 {
-	unsigned int function;
-	unsigned int size;
-	compat_caddr_t data;
-};
-
-struct ncp_fs_info_v2_32 {
-	int version;
-	unsigned int mounted_uid;
-	unsigned int connection;
-	unsigned int buffer_size;
-
-	unsigned int volume_number;
-	__u32 directory_id;
-
-	__u32 dummy1;
-	__u32 dummy2;
-	__u32 dummy3;
-};
-
-struct ncp_objectname_ioctl_32
-{
-	int		auth_type;
-	unsigned int	object_name_len;
-	compat_caddr_t	object_name;	/* an userspace data, in most cases user name */
-};
-
-struct ncp_privatedata_ioctl_32
-{
-	unsigned int	len;
-	compat_caddr_t	data;		/* ~1000 for NDS */
-};
-
-#define	NCP_IOC_NCPREQUEST_32		_IOR('n', 1, struct ncp_ioctl_request_32)
-
-#define NCP_IOC_GETMOUNTUID2_32		_IOW('n', 2, unsigned int)
-
-#define NCP_IOC_GET_FS_INFO_V2_32	_IOWR('n', 4, struct ncp_fs_info_v2_32)
-
-#define NCP_IOC_GETOBJECTNAME_32	_IOWR('n', 9, struct ncp_objectname_ioctl_32)
-#define NCP_IOC_SETOBJECTNAME_32	_IOR('n', 9, struct ncp_objectname_ioctl_32)
-#define NCP_IOC_GETPRIVATEDATA_32	_IOWR('n', 10, struct ncp_privatedata_ioctl_32)
-#define NCP_IOC_SETPRIVATEDATA_32	_IOR('n', 10, struct ncp_privatedata_ioctl_32)
-
-static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_ioctl_request_32 n32;
-	struct ncp_ioctl_request n;
-	mm_segment_t old_fs;
-	int err;
-
-	if (copy_from_user(&n32, (struct ncp_ioctl_request_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.function = n32.function;
-	n.size = n32.size;
-	if (n.size > 65536)
-		return -EINVAL;
-	n.data = vmalloc(65536);	/* 65536 must be same as NCP_PACKET_SIZE_INTERNAL in ncpfs */
-	if (!n.data)
-		return -ENOMEM;
-	err = -EFAULT;
-	if (copy_from_user(n.data, (void *)A(n32.data), n.size))
-		goto out;
-
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_NCPREQUEST, (unsigned long)&n);
-	set_fs (old_fs);
-        if(err <= 0)
-		goto out;
-	if (err > 65536) {
-		err = -EINVAL;
-		goto out;
-	}
-	if (copy_to_user((void *)A(n32.data), n.data, err)) {
-		err = -EFAULT;
-		goto out;
-	}
- out:
-	vfree(n.data);
-	return err;
-}
-
-static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	mm_segment_t old_fs = get_fs();
-	__kernel_uid_t kuid;
-	int err;
-
-	cmd = NCP_IOC_GETMOUNTUID2;
-
-	set_fs(KERNEL_DS);
-	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
-	set_fs(old_fs);
-
-	if (!err)
-		err = put_user(kuid, (unsigned int*)arg);
-
-	return err;
-}
-
-static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	mm_segment_t old_fs = get_fs();
-	struct ncp_fs_info_v2_32 n32;
-	struct ncp_fs_info_v2 n;
-	int err;
-
-	if (copy_from_user(&n32, (struct ncp_fs_info_v2_32*)arg, sizeof(n32)))
-		return -EFAULT;
-	if (n32.version != NCP_GET_FS_INFO_VERSION_V2)
-		return -EINVAL;
-	n.version = NCP_GET_FS_INFO_VERSION_V2;
-
-	set_fs(KERNEL_DS);
-	err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n);
-	set_fs(old_fs);
-
-	if (!err) {
-		n32.version = n.version;
-		n32.mounted_uid = n.mounted_uid;
-		n32.connection = n.connection;
-		n32.buffer_size = n.buffer_size;
-		n32.volume_number = n.volume_number;
-		n32.directory_id = n.directory_id;
-		n32.dummy1 = n.dummy1;
-		n32.dummy2 = n.dummy2;
-		n32.dummy3 = n.dummy3;
-		err = copy_to_user((struct ncp_fs_info_v2_32*)arg, &n32, sizeof(n32)) ? -EFAULT : 0;
-	}
-	return err;
-}
-
-static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_objectname_ioctl_32 n32;
-	struct ncp_objectname_ioctl n;
-	mm_segment_t old_fs;
-	int err;
-	size_t tl;
-
-	if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.object_name_len = tl = n32.object_name_len;
-	if (tl) {
-		n.object_name = kmalloc(tl, GFP_KERNEL);
-		if (!n.object_name)
-			return -ENOMEM;
-	} else {
-		n.object_name = NULL;
-	}
-
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_GETOBJECTNAME, (unsigned long)&n);
-	set_fs (old_fs);
-        if(err)
-		goto out;
-		
-	if (tl > n.object_name_len)
-		tl = n.object_name_len;
-
-	err = -EFAULT;
-	if (tl && copy_to_user((void *)A(n32.object_name), n.object_name, tl))
-		goto out;
-
-	n32.auth_type = n.auth_type;
-	n32.object_name_len = n.object_name_len;
-	
-	if (copy_to_user((struct ncp_objectname_ioctl_32*)arg, &n32, sizeof(n32)))
-		goto out;
-	
-	err = 0;
- out:
- 	if (n.object_name)
-		kfree(n.object_name);
-
-	return err;
-}
-
-static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_objectname_ioctl_32 n32;
-	struct ncp_objectname_ioctl n;
-	mm_segment_t old_fs;
-	int err;
-	size_t tl;
-
-	if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.auth_type = n32.auth_type;
-	n.object_name_len = tl = n32.object_name_len;
-	if (tl) {
-		n.object_name = kmalloc(tl, GFP_KERNEL);
-		if (!n.object_name)
-			return -ENOMEM;
-		err = -EFAULT;
-		if (copy_from_user(n.object_name, (void *)A(n32.object_name), tl))
-			goto out;
-	} else {
-		n.object_name = NULL;
-	}
-	
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_SETOBJECTNAME, (unsigned long)&n);
-	set_fs (old_fs);
-		
- out:
-	if (n.object_name)
-		kfree(n.object_name);
-
-	return err;
-}
-
-static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_privatedata_ioctl_32 n32;
-	struct ncp_privatedata_ioctl n;
-	mm_segment_t old_fs;
-	int err;
-	size_t tl;
-
-	if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.len = tl = n32.len;
-	if (tl) {
-		n.data = kmalloc(tl, GFP_KERNEL);
-		if (!n.data)
-			return -ENOMEM;
-	} else {
-		n.data = NULL;
-	}
-
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)&n);
-	set_fs (old_fs);
-        if(err)
-		goto out;
-		
-	if (tl > n.len)
-		tl = n.len;
-
-	err = -EFAULT;
-	if (tl && copy_to_user((void *)A(n32.data), n.data, tl))
-		goto out;
-
-	n32.len = n.len;
-	
-	if (copy_to_user((struct ncp_privatedata_ioctl_32*)arg, &n32, sizeof(n32)))
-		goto out;
-	
-	err = 0;
- out:
- 	if (n.data)
-		kfree(n.data);
-
-	return err;
-}
-
-static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_privatedata_ioctl_32 n32;
-	struct ncp_privatedata_ioctl n;
-	mm_segment_t old_fs;
-	int err;
-	size_t tl;
-
-	if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.len = tl = n32.len;
-	if (tl) {
-		n.data = kmalloc(tl, GFP_KERNEL);
-		if (!n.data)
-			return -ENOMEM;
-		err = -EFAULT;
-		if (copy_from_user(n.data, (void *)A(n32.data), tl))
-			goto out;
-	} else {
-		n.data = NULL;
-	}
-	
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)&n);
-	set_fs (old_fs);
-		
- out:
-	if (n.data)
-		kfree(n.data);
-
-	return err;
-}
-
-
 #define HANDLE_IOCTL(cmd,handler) { cmd, (ioctl_trans_handler_t)handler, 0 },
 #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl)
 
@@ -350,17 +49,6 @@
 COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
 COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
 
-/* And these ioctls need translation */
-
-/* NCPFS */
-HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest)
-HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2)
-HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2)
-HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname)
-HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname)
-HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata)
-HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
-
 IOCTL_TABLE_END
 
 int ioctl_table_size = ARRAY_SIZE(ioctl_start);
--- diff/arch/ppc64/kernel/irq.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/kernel/irq.c	2004-05-27 18:34:15.000000000 +0100
@@ -370,8 +370,7 @@
 	return 0;
 }
 
-static inline int handle_irq_event(int irq, struct pt_regs *regs,
-				   struct irqaction *action)
+int handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action)
 {
 	int status = 0;
 	int retval = 0;
@@ -482,6 +481,9 @@
 	int cpu = smp_processor_id();
 	irq_desc_t *desc = get_irq_desc(irq);
 	irqreturn_t action_ret;
+#ifdef CONFIG_IRQSTACKS
+	struct thread_info *curtp, *irqtp;
+#endif
 
 	kstat_cpu(cpu).irqs[irq]++;
 
@@ -548,7 +550,22 @@
 	 */
 	for (;;) {
 		spin_unlock(&desc->lock);
-		action_ret = handle_irq_event(irq, regs, action);
+
+#ifdef CONFIG_IRQSTACKS
+		/* Switch to the irq stack to handle this */
+		curtp = current_thread_info();
+		irqtp = hardirq_ctx[smp_processor_id()];
+		if (curtp != irqtp) {
+			irqtp->task = curtp->task;
+			irqtp->flags = 0;
+			action_ret = call_handle_irq_event(irq, regs, action, irqtp);
+			irqtp->task = NULL;
+			if (irqtp->flags)
+				set_bits(irqtp->flags, &curtp->flags);
+		} else
+#endif
+			action_ret = handle_irq_event(irq, regs, action);
+
 		spin_lock(&desc->lock);
 		if (!noirqdebug)
 			note_interrupt(irq, desc, action_ret);
@@ -690,6 +707,7 @@
 	once++;
 
 	ppc_md.init_IRQ();
+	irq_ctx_init();
 }
 
 static struct proc_dir_entry * root_irq_dir;
@@ -973,4 +991,51 @@
 
 }
 
-#endif
+#endif /* CONFIG_PPC_ISERIES */
+
+#ifdef CONFIG_IRQSTACKS
+struct thread_info *softirq_ctx[NR_CPUS];
+struct thread_info *hardirq_ctx[NR_CPUS];
+
+void irq_ctx_init(void)
+{
+	struct thread_info *tp;
+	int i;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
+		tp = softirq_ctx[i];
+		tp->cpu = i;
+		tp->preempt_count = SOFTIRQ_OFFSET;
+
+		memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
+		tp = hardirq_ctx[i];
+		tp->cpu = i;
+		tp->preempt_count = HARDIRQ_OFFSET;
+	}
+}
+
+void do_softirq(void)
+{
+	unsigned long flags;
+	struct thread_info *curtp, *irqtp;
+
+	if (in_interrupt())
+		return;
+
+	local_irq_save(flags);
+
+	if (local_softirq_pending()) {
+		curtp = current_thread_info();
+		irqtp = softirq_ctx[smp_processor_id()];
+		irqtp->task = curtp->task;
+		call_do_softirq(irqtp);
+		irqtp->task = NULL;
+	}
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(do_softirq);
+
+#endif /* CONFIG_IRQSTACKS */
+
--- diff/arch/ppc64/kernel/misc.S	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/kernel/misc.S	2004-05-27 18:34:15.000000000 +0100
@@ -102,6 +102,30 @@
 	blr
 #endif /* CONFIG_PPC_ISERIES */
 
+#ifdef CONFIG_IRQSTACKS
+_GLOBAL(call_do_softirq)
+	mflr	r0
+	std	r0,16(r1)
+	stdu	r1,THREAD_SIZE-112(r3)
+	mr	r1,r3
+	bl	.__do_softirq
+	ld	r1,0(r1)
+	ld	r0,16(r1)
+	mtlr	r0
+	blr
+
+_GLOBAL(call_handle_irq_event)
+	mflr	r0
+	std	r0,16(r1)
+	stdu	r1,THREAD_SIZE-112(r6)
+	mr	r1,r6
+	bl	.handle_irq_event
+	ld	r1,0(r1)
+	ld	r0,16(r1)
+	mtlr	r0
+	blr
+#endif /* CONFIG_IRQSTACKS */
+
 /*
  * Flush instruction cache.
  */
--- diff/arch/ppc64/kernel/process.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/kernel/process.c	2004-05-27 18:34:15.000000000 +0100
@@ -457,16 +457,28 @@
 
 static int kstack_depth_to_print = 64;
 
-static inline int validate_sp(unsigned long sp, struct task_struct *p)
+static int validate_sp(unsigned long sp, struct task_struct *p,
+		       unsigned long nbytes)
 {
 	unsigned long stack_page = (unsigned long)p->thread_info;
 
-	if (sp < stack_page + sizeof(struct thread_struct))
-		return 0;
-	if (sp >= stack_page + THREAD_SIZE)
-		return 0;
+	if (sp >= stack_page + sizeof(struct thread_struct)
+	    && sp <= stack_page + THREAD_SIZE - nbytes)
+		return 1;
+
+#ifdef CONFIG_IRQSTACKS
+	stack_page = (unsigned long) hardirq_ctx[task_cpu(p)];
+	if (sp >= stack_page + sizeof(struct thread_struct)
+	    && sp <= stack_page + THREAD_SIZE - nbytes)
+		return 1;
+
+	stack_page = (unsigned long) softirq_ctx[task_cpu(p)];
+	if (sp >= stack_page + sizeof(struct thread_struct)
+	    && sp <= stack_page + THREAD_SIZE - nbytes)
+		return 1;
+#endif
 
-	return 1;
+	return 0;
 }
 
 unsigned long get_wchan(struct task_struct *p)
@@ -478,12 +490,12 @@
 		return 0;
 
 	sp = p->thread.ksp;
-	if (!validate_sp(sp, p))
+	if (!validate_sp(sp, p, 112))
 		return 0;
 
 	do {
 		sp = *(unsigned long *)sp;
-		if (!validate_sp(sp, p))
+		if (!validate_sp(sp, p, 112))
 			return 0;
 		if (count > 0) {
 			ip = *(unsigned long *)(sp + 16);
@@ -496,9 +508,10 @@
 
 void show_stack(struct task_struct *p, unsigned long *_sp)
 {
-	unsigned long ip;
+	unsigned long ip, newsp, lr;
 	int count = 0;
 	unsigned long sp = (unsigned long)_sp;
+	int firstframe = 1;
 
 	if (sp == 0) {
 		if (p) {
@@ -509,17 +522,40 @@
 		}
 	}
 
-	if (!validate_sp(sp, p))
-		return;
-
+	lr = 0;
 	printk("Call Trace:\n");
 	do {
-		sp = *(unsigned long *)sp;
-		if (!validate_sp(sp, p))
+		if (!validate_sp(sp, p, 112))
 			return;
-		ip = *(unsigned long *)(sp + 16);
-		printk("[%016lx] ", ip);
-		print_symbol("%s\n", ip);
+
+		_sp = (unsigned long *) sp;
+		newsp = _sp[0];
+		ip = _sp[2];
+		if (!firstframe || ip != lr) {
+			printk("[%016lx] [%016lx] ", sp, ip);
+			print_symbol("%s", ip);
+			if (firstframe)
+				printk(" (unreliable)");
+			printk("\n");
+		}
+		firstframe = 0;
+
+		/*
+		 * See if this is an exception frame.
+		 * We look for the "regshere" marker in the current frame.
+		 */
+		if (validate_sp(sp, p, sizeof(struct pt_regs) + 400)
+		    && _sp[12] == 0x7265677368657265) {
+			struct pt_regs *regs = (struct pt_regs *)
+				(sp + STACK_FRAME_OVERHEAD);
+			printk("--- Exception: %lx", regs->trap);
+			print_symbol(" at %s\n", regs->nip);
+			lr = regs->link;
+			print_symbol("    LR = %s\n", lr);
+			firstframe = 1;
+		}
+
+		sp = newsp;
 	} while (count++ < kstack_depth_to_print);
 }
 
--- diff/arch/ppc64/kernel/prom.c	2004-05-19 22:11:18.000000000 +0100
+++ source/arch/ppc64/kernel/prom.c	2004-05-27 18:34:15.000000000 +0100
@@ -2189,11 +2189,13 @@
 		ints = imap - nintrc;
 		reg = ints - naddrc;
 	}
+	if (p == NULL) {
 #ifdef DEBUG_IRQ
-	if (p == NULL)
 		printk("hmmm, int tree for %s doesn't have ctrler\n",
 		       np->full_name);
 #endif
+		return 0;
+	}
 	*irq = ints;
 	*ictrler = p;
 	return nintrc;
@@ -2204,7 +2206,7 @@
 		       int measure_only)
 {
 	unsigned int *ints;
-	int intlen, intrcells;
+	int intlen, intrcells, intrcount;
 	int i, j, n;
 	unsigned int *irq, virq;
 	struct device_node *ic;
@@ -2214,34 +2216,40 @@
 		return mem_start;
 	intrcells = prom_n_intr_cells(np);
 	intlen /= intrcells * sizeof(unsigned int);
-	np->n_intrs = intlen;
 	np->intrs = (struct interrupt_info *) mem_start;
 	mem_start += intlen * sizeof(struct interrupt_info);
 
 	if (measure_only)
 		return mem_start;
 
-	for (i = 0; i < intlen; ++i) {
-		np->intrs[i].line = 0;
-		np->intrs[i].sense = 1;
+	intrcount = 0;
+	for (i = 0; i < intlen; ++i, ints += intrcells) {
 		n = map_interrupt(&irq, &ic, np, ints, intrcells);
 		if (n <= 0)
 			continue;
-		virq = virt_irq_create_mapping(irq[0]);
-		if (virq == NO_IRQ) {
-			printk(KERN_CRIT "Could not allocate interrupt "
-			       "number for %s\n", np->full_name);
-		} else
-			np->intrs[i].line = irq_offset_up(virq);
+
+		/* don't map IRQ numbers under a cascaded 8259 controller */
+		if (ic && device_is_compatible(ic, "chrp,iic")) {
+			np->intrs[intrcount].line = irq[0];
+		} else {
+			virq = virt_irq_create_mapping(irq[0]);
+			if (virq == NO_IRQ) {
+				printk(KERN_CRIT "Could not allocate interrupt"
+				       " number for %s\n", np->full_name);
+				continue;
+			}
+			np->intrs[intrcount].line = irq_offset_up(virq);
+		}
 
 		/* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
 		if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) {
 			char *name = get_property(ic->parent, "name", NULL);
 			if (name && !strcmp(name, "u3"))
-				np->intrs[i].line += 128;
+				np->intrs[intrcount].line += 128;
 		}
+		np->intrs[intrcount].sense = 1;
 		if (n > 1)
-			np->intrs[i].sense = irq[1];
+			np->intrs[intrcount].sense = irq[1];
 		if (n > 2) {
 			printk("hmmm, got %d intr cells for %s:", n,
 			       np->full_name);
@@ -2249,8 +2257,9 @@
 				printk(" %d", irq[j]);
 			printk("\n");
 		}
-		ints += intrcells;
+		++intrcount;
 	}
+	np->n_intrs = intrcount;
 
 	return mem_start;
 }
--- diff/arch/ppc64/kernel/rtas-proc.c	2004-05-19 22:11:19.000000000 +0100
+++ source/arch/ppc64/kernel/rtas-proc.c	2004-05-27 18:34:15.000000000 +0100
@@ -541,7 +541,7 @@
 		case SENSOR_BUSY:
 			return "(busy)";
 		case SENSOR_NOT_EXIST:
-			return "(non existant)";
+			return "(non existent)";
 		case SENSOR_DR_ENTITY:
 			return "(dr entity removed)";
 		default:
@@ -698,7 +698,7 @@
 			}
 			break;
 		default:
-			n += sprintf(buf+n,  "Unkown sensor (type %d), ignoring it\n",
+			n += sprintf(buf+n,  "Unknown sensor (type %d), ignoring it\n",
 					s.token);
 			unknown = 1;
 			have_strings = 1;
--- diff/arch/ppc64/kernel/setup.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -82,7 +82,6 @@
 
 int powersave_nap;
 
-char saved_command_line[COMMAND_LINE_SIZE];
 unsigned char aux_device_present;
 
 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
@@ -572,6 +571,23 @@
 
 extern void (*calibrate_delay)(void);
 
+#ifdef CONFIG_IRQSTACKS
+static void __init irqstack_early_init(void)
+{
+	int i;
+
+	/* interrupt stacks must be under 256MB, we cannot afford to take SLB misses on them */
+	for (i = 0; i < NR_CPUS; i++) {
+		softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE,
+					THREAD_SIZE, 0x10000000));
+		hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE,
+					THREAD_SIZE, 0x10000000));
+	}
+}
+#else
+#define irqstack_early_init()
+#endif
+
 /*
  * Called into from start_kernel, after lock_kernel has been called.
  * Initializes bootmem, which is unsed to manage page allocation until
@@ -617,6 +633,8 @@
 	strlcpy(saved_command_line, cmd_line, sizeof(saved_command_line));
 	*cmdline_p = cmd_line;
 
+	irqstack_early_init();
+
 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
 
--- diff/arch/ppc64/kernel/viopath.c	2004-05-19 22:11:19.000000000 +0100
+++ source/arch/ppc64/kernel/viopath.c	2004-05-27 18:34:15.000000000 +0100
@@ -190,6 +190,8 @@
 static int proc_viopath_show(struct seq_file *m, void *v)
 {
 	char *buf;
+	u16 vlanMap;
+	int vlanIndex;
 	dma_addr_t handle;
 	HvLpEvent_Rc hvrc;
 	DECLARE_MUTEX_LOCKED(Semaphore);
@@ -216,12 +218,18 @@
 
 	down(&Semaphore);
 
-	dma_unmap_single(iSeries_vio_dev, handle, PAGE_SIZE, DMA_FROM_DEVICE);
-	kfree(buf);
+	vlanMap = HvLpConfig_getVirtualLanIndexMap();
+	vlanIndex = 0;
+	while (vlanMap != 0){
+		if (vlanMap & 0x8000)
+			vlanIndex++;;
+		vlanMap = vlanMap << 1;
+	}
 
-	buf[PAGE_SIZE] = '\0';
+	buf[PAGE_SIZE-1] = '\0';
 	seq_printf(m, "%s", buf);
 
+	seq_printf(m, "AVAILABLE_VETH=%d\n", vlanIndex );
 	seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n",
 		   e2a(xItExtVpdPanel.mfgID[2]),
 		   e2a(xItExtVpdPanel.mfgID[3]),
@@ -231,6 +239,9 @@
 		   e2a(xItExtVpdPanel.systemSerial[4]),
 		   e2a(xItExtVpdPanel.systemSerial[5]));
 
+	dma_unmap_single(iSeries_vio_dev, handle, PAGE_SIZE, DMA_FROM_DEVICE);
+	kfree(buf);
+
 	return 0;
 }
 
--- diff/arch/ppc64/kernel/xics.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/kernel/xics.c	2004-05-27 18:34:15.000000000 +0100
@@ -620,7 +620,7 @@
 	cpumask_t tmp = CPU_MASK_NONE;
 
 	irq = virt_irq_to_real(irq_offset_down(virq));
-	if (irq == XICS_IPI)
+	if (irq == XICS_IPI || irq == NO_IRQ)
 		return;
 
 	status = rtas_call(ibm_get_xive, 1, 3, (void *)&xics_status, irq);
--- diff/arch/ppc64/mm/fault.c	2004-05-19 22:11:19.000000000 +0100
+++ source/arch/ppc64/mm/fault.c	2004-05-27 18:34:15.000000000 +0100
@@ -75,6 +75,8 @@
 	return 0;
 }
 
+int check_exception(struct pt_regs *regs);
+
 /*
  * The error_code parameter is
  *  - DSISR for a non-SLB data access fault,
@@ -110,7 +112,29 @@
 		bad_page_fault(regs, address, SIGSEGV);
 		return;
 	}
-	down_read(&mm->mmap_sem);
+
+	/* When running in the kernel we expect faults to occur only to
+	 * addresses in user space.  All other faults represent errors in the
+	 * kernel and should generate an OOPS.  Unfortunatly, in the case of an
+	 * erroneous fault occuring in a code path which already holds mmap_sem
+	 * we will deadlock attempting to validate the fault against the
+	 * address space.  Luckily the kernel only validly references user
+	 * space from well defined areas of code, which are listed in the
+	 * exceptions table.
+	 *
+	 * As the vast majority of faults will be valid we will only perform
+	 * the source reference check when there is a possibilty of a deadlock.
+	 * Attempt to lock the address space, if we cannot we then validate the
+	 * source.  If this is invalid we can skip the address space check,
+	 * thus avoiding the deadlock.
+	 */
+	if (!down_read_trylock(&mm->mmap_sem)) {
+		if (!user_mode(regs) && !check_exception(regs))
+			goto bad_area_nosemaphore;
+
+		down_read(&mm->mmap_sem);
+	}
+
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -200,6 +224,7 @@
 bad_area:
 	up_read(&mm->mmap_sem);
 
+bad_area_nosemaphore:
 	/* User mode accesses cause a SIGSEGV */
 	if (user_mode(regs)) {
 		info.si_signo = SIGSEGV;
@@ -259,3 +284,15 @@
 	/* kernel has accessed a bad area */
 	die("Kernel access of bad area", regs, sig);
 }
+
+int check_exception(struct pt_regs *regs)
+{
+	const struct exception_table_entry *entry;
+
+	/* Are we prepared to handle this fault?  */
+	if ((entry = search_exception_tables(regs->nip)) != NULL) {
+		return 1;
+	}
+
+	return 0;
+}
--- diff/arch/ppc64/mm/init.c	2004-05-19 22:11:19.000000000 +0100
+++ source/arch/ppc64/mm/init.c	2004-05-27 18:34:15.000000000 +0100
@@ -407,7 +407,7 @@
 	area = im_get_area((unsigned long) addr, size, 
 			    IM_REGION_EXISTS | IM_REGION_SUBSET);
 	if (area == NULL) {
-		printk(KERN_ERR "%s() cannot unmap nonexistant range 0x%lx\n",
+		printk(KERN_ERR "%s() cannot unmap nonexistent range 0x%lx\n",
 				__FUNCTION__, (unsigned long) addr);
 		return 1;
 	}
--- diff/arch/ppc64/mm/numa.c	2004-05-19 22:11:19.000000000 +0100
+++ source/arch/ppc64/mm/numa.c	2004-05-27 18:34:15.000000000 +0100
@@ -19,7 +19,7 @@
 #include <asm/abs_addr.h>
 
 #if 1
-#define dbg(args...) udbg_printf(args)
+#define dbg(args...) printk(KERN_INFO args)
 #else
 #define dbg(args...)
 #endif
@@ -56,16 +56,136 @@
 	}
 }
 
+static struct device_node * __init find_cpu_node(unsigned int cpu)
+{
+	unsigned int hw_cpuid = get_hard_smp_processor_id(cpu);
+	struct device_node *cpu_node = NULL;
+	unsigned int *interrupt_server, *reg;
+	int len;
+
+	while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) {
+		/* Try interrupt server first */
+		interrupt_server = (unsigned int *)get_property(cpu_node,
+					"ibm,ppc-interrupt-server#s", &len);
+
+		if (interrupt_server && (len > 0)) {
+			while (len--) {
+				if (interrupt_server[len-1] == hw_cpuid)
+					return cpu_node;
+			}
+		} else {
+			reg = (unsigned int *)get_property(cpu_node,
+							   "reg", &len);
+			if (reg && (len > 0) && (reg[0] == hw_cpuid))
+				return cpu_node;
+		}
+	}
+
+	return NULL;
+}
+
+/* must hold reference to node during call */
+static int *of_get_associativity(struct device_node *dev)
+ {
+	unsigned int *result;
+	int len;
+
+	result = (unsigned int *)get_property(dev, "ibm,associativity", &len);
+
+	if (len <= 0)
+		return NULL;
+
+	return result;
+}
+
+static int of_node_numa_domain(struct device_node *device, int depth)
+{
+	int numa_domain;
+	unsigned int *tmp;
+
+	tmp = of_get_associativity(device);
+	if (tmp && (tmp[0] >= depth)) {
+		numa_domain = tmp[depth];
+	} else {
+		printk(KERN_ERR "WARNING: no NUMA information for "
+		       "%s\n", device->full_name);
+		numa_domain = 0;
+	}
+	return numa_domain;
+}
+
+/*
+ * In theory, the "ibm,associativity" property may contain multiple
+ * associativity lists because a resource may be multiply connected
+ * into the machine.  This resource then has different associativity
+ * characteristics relative to its multiple connections.  We ignore
+ * this for now.  We also assume that all cpu and memory sets have
+ * their distances represented at a common level.  This won't be
+ * true for heirarchical NUMA.
+ *
+ * In any case the ibm,associativity-reference-points should give
+ * the correct depth for a normal NUMA system.
+ *
+ * - Dave Hansen <haveblue@us.ibm.com>
+ */
+static int find_min_common_depth(void)
+{
+	int depth;
+	unsigned int *ref_points;
+	struct device_node *rtas_root;
+	unsigned int len;
+
+	rtas_root = of_find_node_by_path("/rtas");
+
+	if (!rtas_root) {
+		printk(KERN_ERR "WARNING: %s() could not find rtas root\n",
+				__FUNCTION__);
+		return -1;
+	}
+
+	/*
+	 * this property is 2 32-bit integers, each representing a level of
+	 * depth in the associativity nodes.  The first is for an SMP
+	 * configuration (should be all 0's) and the second is for a normal
+	 * NUMA configuration.
+	 */
+	ref_points = (unsigned int *)get_property(rtas_root,
+			"ibm,associativity-reference-points", &len);
+
+	if ((len >= 1) && ref_points) {
+		depth = ref_points[1];
+	} else {
+		printk(KERN_ERR "WARNING: could not find NUMA "
+				"associativity reference point\n");
+		depth = -1;
+	}
+	of_node_put(rtas_root);
+
+	return depth;
+}
+
+static unsigned long read_cell_ul(struct device_node *device, unsigned int **buf)
+{
+	int i;
+	unsigned long result = 0;
+
+	i = prom_n_size_cells(device);
+	/* bug on i>2 ?? */
+	while (i--) {
+		result = (result << 32) | **buf;
+		(*buf)++;
+	}
+	return result;
+}
+
 static int __init parse_numa_properties(void)
 {
 	struct device_node *cpu = NULL;
 	struct device_node *memory = NULL;
-	int *cpu_associativity;
-	int *memory_associativity;
 	int depth;
 	int max_domain = 0;
 	long entries = lmb_end_of_DRAM() >> MEMORY_INCREMENT_SHIFT;
-	long i;
+	unsigned long i;
 
 	if (strstr(saved_command_line, "numa=off")) {
 		printk(KERN_WARNING "NUMA disabled by user\n");
@@ -78,112 +198,78 @@
 	for (i = 0; i < entries ; i++)
 		numa_memory_lookup_table[i] = ARRAY_INITIALISER;
 
-	cpu = of_find_node_by_type(NULL, "cpu");
-	if (!cpu)
-		goto err;
-
-	memory = of_find_node_by_type(NULL, "memory");
-	if (!memory)
-		goto err;
-
-	cpu_associativity = (int *)get_property(cpu, "ibm,associativity", NULL);
-	if (!cpu_associativity)
-		goto err;
-
-	memory_associativity = (int *)get_property(memory, "ibm,associativity",
-						   NULL);
-	if (!memory_associativity)
-		goto err;
-
-	/* find common depth */
-	if (cpu_associativity[0] < memory_associativity[0])
-		depth = cpu_associativity[0];
-	else
-		depth = memory_associativity[0];
-
-	for (; cpu; cpu = of_find_node_by_type(cpu, "cpu")) {
-		int *tmp;
-		int cpu_nr, numa_domain;
+	depth = find_min_common_depth();
 
-		tmp = (int *)get_property(cpu, "reg", NULL);
-		if (!tmp)
-			continue;
-		cpu_nr = *tmp;
+	printk(KERN_INFO "NUMA associativity depth for CPU/Memory: %d\n", depth);
+	if (depth < 0)
+		return depth;
 
-		tmp = (int *)get_property(cpu, "ibm,associativity",
-					  NULL);
-		if (!tmp)
-			continue;
-		numa_domain = tmp[depth];
+	for_each_cpu(i) {
+		int numa_domain;
+
+		cpu = find_cpu_node(i);
 
-		/* FIXME */
-		if (numa_domain == 0xffff) {
-			dbg("cpu %d has no numa doman\n", cpu_nr);
+		if (cpu) {
+			numa_domain = of_node_numa_domain(cpu, depth);
+			of_node_put(cpu);
+
+			if (numa_domain >= MAX_NUMNODES) {
+				/*
+			 	 * POWER4 LPAR uses 0xffff as invalid node,
+				 * dont warn in this case.
+			 	 */
+				if (numa_domain != 0xffff)
+					printk(KERN_ERR "WARNING: cpu %ld "
+					       "maps to invalid NUMA node %d\n",
+					       i, numa_domain);
+				numa_domain = 0;
+			}
+		} else {
+			printk(KERN_ERR "WARNING: no NUMA information for "
+			       "cpu %ld\n", i);
 			numa_domain = 0;
 		}
 
-		if (numa_domain >= MAX_NUMNODES)
-			BUG();
-
 		node_set_online(numa_domain);
 
 		if (max_domain < numa_domain)
 			max_domain = numa_domain;
 
-		map_cpu_to_node(cpu_nr, numa_domain);
-		/* register the second thread on an SMT machine */
-		if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
-			map_cpu_to_node(cpu_nr ^ 0x1, numa_domain);
+		map_cpu_to_node(i, numa_domain);
 	}
 
-	for (; memory; memory = of_find_node_by_type(memory, "memory")) {
-		unsigned int *tmp1, *tmp2;
-		unsigned long i;
-		unsigned long start = 0;
-		unsigned long size = 0;
+	memory = NULL;
+	while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+		unsigned long start;
+		unsigned long size;
 		int numa_domain;
 		int ranges;
+		unsigned int *memcell_buf;
+		unsigned int len;
 
-		tmp1 = (int *)get_property(memory, "reg", NULL);
-		if (!tmp1)
+		memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+		if (!memcell_buf || len <= 0)
 			continue;
 
 		ranges = memory->n_addrs;
 new_range:
-
-		i = prom_n_size_cells(memory);
-		while (i--) {
-			start = (start << 32) | *tmp1;
-			tmp1++;
-		}
-
-		i = prom_n_size_cells(memory);
-		while (i--) {
-			size = (size << 32) | *tmp1;
-			tmp1++;
-		}
+		/* these are order-sensitive, and modify the buffer pointer */
+		start = read_cell_ul(memory, &memcell_buf);
+		size = read_cell_ul(memory, &memcell_buf);
 
 		start = _ALIGN_DOWN(start, MEMORY_INCREMENT);
 		size = _ALIGN_UP(size, MEMORY_INCREMENT);
 
-		if ((start + size) > MAX_MEMORY)
-			BUG();
+		numa_domain = of_node_numa_domain(memory, depth);
 
-		tmp2 = (int *)get_property(memory, "ibm,associativity",
-					   NULL);
-		if (!tmp2)
-			continue;
-		numa_domain = tmp2[depth];
-
-		/* FIXME */
-		if (numa_domain == 0xffff) {
-			dbg("memory has no numa doman\n");
+		if (numa_domain >= MAX_NUMNODES) {
+			if (numa_domain != 0xffff)
+				printk(KERN_ERR "WARNING: memory at %lx maps "
+				       "to invalid NUMA node %d\n", start,
+				       numa_domain);
 			numa_domain = 0;
 		}
 
-		if (numa_domain >= MAX_NUMNODES)
-			BUG();
-
 		node_set_online(numa_domain);
 
 		if (max_domain < numa_domain)
@@ -205,11 +291,13 @@
 						start, size);
 				continue;
 			}
-			node_data[numa_domain].node_spanned_pages += size / PAGE_SIZE;
+			node_data[numa_domain].node_spanned_pages +=
+				size / PAGE_SIZE;
 		} else {
 			node_data[numa_domain].node_start_pfn =
 				start / PAGE_SIZE;
-			node_data[numa_domain].node_spanned_pages = size / PAGE_SIZE;
+			node_data[numa_domain].node_spanned_pages =
+				size / PAGE_SIZE;
 		}
 
 		for (i = start ; i < (start+size); i += MEMORY_INCREMENT)
@@ -227,10 +315,6 @@
 	numnodes = max_domain + 1;
 
 	return 0;
-err:
-	of_node_put(cpu);
-	of_node_put(memory);
-	return -1;
 }
 
 static void __init setup_nonnuma(void)
--- diff/arch/ppc64/mm/tlb.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/mm/tlb.c	2004-05-27 18:34:15.000000000 +0100
@@ -41,6 +41,33 @@
 DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
 unsigned long pte_freelist_forced_free;
 
+void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)
+{
+	/* This is safe as we are holding page_table_lock */
+        cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
+	struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
+
+	if (atomic_read(&tlb->mm->mm_users) < 2 ||
+	    cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
+		pte_free(ptepage);
+		return;
+	}
+
+	if (*batchp == NULL) {
+		*batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
+		if (*batchp == NULL) {
+			pte_free_now(ptepage);
+			return;
+		}
+		(*batchp)->index = 0;
+	}
+	(*batchp)->pages[(*batchp)->index++] = ptepage;
+	if ((*batchp)->index == PTE_FREELIST_SIZE) {
+		pte_free_submit(*batchp);
+		*batchp = NULL;
+	}
+}
+
 /*
  * Update the MMU hash table to correspond with a change to
  * a Linux PTE.  If wrprot is true, it is permissible to
--- diff/arch/ppc64/xmon/xmon.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/ppc64/xmon/xmon.c	2004-05-27 18:34:15.000000000 +0100
@@ -273,7 +273,7 @@
 		args.args[0] = SURVEILLANCE_TOKEN;
 		args.args[1] = 0;
 		args.args[2] = 0;
-		enter_rtas((void *) __pa(&args));
+		enter_rtas(__pa(&args));
 	}
 #endif
 }
@@ -1399,8 +1399,7 @@
 
 		/* Look for "regshere" marker to see if this is
 		   an exception frame. */
-		if (newsp - sp == sizeof(struct pt_regs) + 400
-		    && mread(sp + 0x60, &marker, sizeof(unsigned long))
+		if (mread(sp + 0x60, &marker, sizeof(unsigned long))
 		    && marker == 0x7265677368657265) {
 			if (mread(sp + 0x70, &regs, sizeof(regs))
 			    != sizeof(regs)) {
@@ -1417,12 +1416,6 @@
 
 		if (newsp == 0)
 			break;
-		if (newsp < sp) {
-			printf("Stack chain goes %s: %.16lx\n",
-			       (newsp < KERNELBASE? "into userspace":
-				"backwards"), newsp);
-			break;
-		}
 
 		sp = newsp;
 	} while (count++ < xmon_depth_to_print);
--- diff/arch/s390/kernel/init_task.c	2004-05-19 22:11:20.000000000 +0100
+++ source/arch/s390/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/s390/kernel/setup.c	2004-05-19 22:11:20.000000000 +0100
+++ source/arch/s390/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -74,7 +74,6 @@
 #include <asm/setup.h>
 
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
 
 static struct resource code_resource = { "Kernel code", 0x100000, 0 };
 static struct resource data_resource = { "Kernel data", 0, 0 };
--- diff/arch/sh/kernel/init_task.c	2004-05-19 22:11:22.000000000 +0100
+++ source/arch/sh/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/sh/kernel/setup.c	2004-05-19 22:11:22.000000000 +0100
+++ source/arch/sh/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -85,14 +85,12 @@
 #define INITRD_SIZE (*(unsigned long *) (PARAM+0x014))
 /* ... */
 #define COMMAND_LINE ((char *) (PARAM+0x100))
-#define COMMAND_LINE_SIZE 256
 
 #define RAMDISK_IMAGE_START_MASK  	0x07FF
 #define RAMDISK_PROMPT_FLAG		0x8000
 #define RAMDISK_LOAD_FLAG		0x4000	
 
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
 
 struct resource standard_io_resources[] = {
 	{ "dma1", 0x00, 0x1f },
--- diff/arch/sparc/kernel/init_task.c	2004-05-19 22:11:22.000000000 +0100
+++ source/arch/sparc/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
--- diff/arch/sparc/kernel/setup.c	2004-05-19 22:11:23.000000000 +0100
+++ source/arch/sparc/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -244,8 +244,7 @@
 
 extern int root_mountflags;
 
-char saved_command_line[256];
-char reboot_command[256];
+char reboot_command[COMMAND_LINE_SIZE];
 enum sparc_cpu sparc_cpu_model;
 
 struct tt_entry *sparc_ttable;
--- diff/arch/sparc/kernel/sparc_ksyms.c	2004-05-19 22:11:23.000000000 +0100
+++ source/arch/sparc/kernel/sparc_ksyms.c	2004-05-27 18:34:15.000000000 +0100
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -74,7 +75,6 @@
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
-extern char saved_command_line[];
 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
--- diff/arch/sparc64/Kconfig	2004-05-19 22:11:23.000000000 +0100
+++ source/arch/sparc64/Kconfig	2004-05-27 18:34:15.000000000 +0100
@@ -687,12 +687,19 @@
 	depends on DEBUG_KERNEL
 	bool "Debug BOOTMEM initialization"
 
+config LOCKMETER
+	bool "Kernel lock metering"
+	depends on SMP && !PREEMPT
+	help
+	  Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+	  but allows you to see various statistics using the lockstat command.
+
 # We have a custom atomic_dec_and_lock() implementation but it's not
 # compatible with spinlock debugging so we need to fall back on
 # the generic version in that case.
 config HAVE_DEC_LOCK
 	bool
-	depends on SMP && !DEBUG_SPINLOCK
+	depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER
 	default y
 
 config MCOUNT
--- diff/arch/sparc64/kernel/init_task.c	2004-05-19 22:11:24.000000000 +0100
+++ source/arch/sparc64/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
--- diff/arch/sparc64/kernel/ioctl32.c	2004-05-19 22:11:24.000000000 +0100
+++ source/arch/sparc64/kernel/ioctl32.c	2004-05-27 18:34:15.000000000 +0100
@@ -148,306 +148,6 @@
 	return ret;
 }
 
-struct ncp_ioctl_request_32 {
-	unsigned int function;
-	unsigned int size;
-	compat_caddr_t data;
-};
-
-struct ncp_fs_info_v2_32 {
-	int version;
-	unsigned int mounted_uid;
-	unsigned int connection;
-	unsigned int buffer_size;
-
-	unsigned int volume_number;
-	__u32 directory_id;
-
-	__u32 dummy1;
-	__u32 dummy2;
-	__u32 dummy3;
-};
-
-struct ncp_objectname_ioctl_32
-{
-	int		auth_type;
-	unsigned int	object_name_len;
-	compat_caddr_t	object_name;	/* an userspace data, in most cases user name */
-};
-
-struct ncp_privatedata_ioctl_32
-{
-	unsigned int	len;
-	compat_caddr_t	data;		/* ~1000 for NDS */
-};
-
-#define	NCP_IOC_NCPREQUEST_32		_IOR('n', 1, struct ncp_ioctl_request_32)
-
-#define NCP_IOC_GETMOUNTUID2_32		_IOW('n', 2, unsigned int)
-
-#define NCP_IOC_GET_FS_INFO_V2_32	_IOWR('n', 4, struct ncp_fs_info_v2_32)
-
-#define NCP_IOC_GETOBJECTNAME_32	_IOWR('n', 9, struct ncp_objectname_ioctl_32)
-#define NCP_IOC_SETOBJECTNAME_32	_IOR('n', 9, struct ncp_objectname_ioctl_32)
-#define NCP_IOC_GETPRIVATEDATA_32	_IOWR('n', 10, struct ncp_privatedata_ioctl_32)
-#define NCP_IOC_SETPRIVATEDATA_32	_IOR('n', 10, struct ncp_privatedata_ioctl_32)
-
-static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_ioctl_request_32 n32;
-	struct ncp_ioctl_request n;
-	mm_segment_t old_fs;
-	int err;
-
-	if (copy_from_user(&n32, (struct ncp_ioctl_request_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.function = n32.function;
-	n.size = n32.size;
-	if (n.size > 65536)
-		return -EINVAL;
-	n.data = vmalloc(65536);	/* 65536 must be same as NCP_PACKET_SIZE_INTERNAL in ncpfs */
-	if (!n.data)
-		return -ENOMEM;
-	err = -EFAULT;
-	if (copy_from_user(n.data, A(n32.data), n.size))
-		goto out;
-
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_NCPREQUEST, (unsigned long)&n);
-	set_fs (old_fs);
-        if(err <= 0)
-		goto out;
-	if (err > 65536) {
-		err = -EINVAL;
-		goto out;
-	}
-	if (copy_to_user(A(n32.data), n.data, err)) {
-		err = -EFAULT;
-		goto out;
-	}
- out:
-	vfree(n.data);
-	return err;
-}
-
-static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	mm_segment_t old_fs = get_fs();
-	__kernel_uid_t kuid;
-	int err;
-
-	cmd = NCP_IOC_GETMOUNTUID2;
-
-	set_fs(KERNEL_DS);
-	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
-	set_fs(old_fs);
-
-	if (!err)
-		err = put_user(kuid, (unsigned int*)arg);
-
-	return err;
-}
-
-static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	mm_segment_t old_fs = get_fs();
-	struct ncp_fs_info_v2_32 n32;
-	struct ncp_fs_info_v2 n;
-	int err;
-
-	if (copy_from_user(&n32, (struct ncp_fs_info_v2_32*)arg, sizeof(n32)))
-		return -EFAULT;
-	if (n32.version != NCP_GET_FS_INFO_VERSION_V2)
-		return -EINVAL;
-	n.version = NCP_GET_FS_INFO_VERSION_V2;
-
-	set_fs(KERNEL_DS);
-	err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n);
-	set_fs(old_fs);
-
-	if (!err) {
-		n32.version = n.version;
-		n32.mounted_uid = n.mounted_uid;
-		n32.connection = n.connection;
-		n32.buffer_size = n.buffer_size;
-		n32.volume_number = n.volume_number;
-		n32.directory_id = n.directory_id;
-		n32.dummy1 = n.dummy1;
-		n32.dummy2 = n.dummy2;
-		n32.dummy3 = n.dummy3;
-		err = copy_to_user((struct ncp_fs_info_v2_32*)arg, &n32, sizeof(n32)) ? -EFAULT : 0;
-	}
-	return err;
-}
-
-static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_objectname_ioctl_32 n32;
-	struct ncp_objectname_ioctl n;
-	mm_segment_t old_fs;
-	int err;
-	size_t tl;
-
-	if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.object_name_len = tl = n32.object_name_len;
-	if (tl) {
-		n.object_name = kmalloc(tl, GFP_KERNEL);
-		if (!n.object_name)
-			return -ENOMEM;
-	} else {
-		n.object_name = NULL;
-	}
-
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_GETOBJECTNAME, (unsigned long)&n);
-	set_fs (old_fs);
-        if(err)
-		goto out;
-		
-	if (tl > n.object_name_len)
-		tl = n.object_name_len;
-
-	err = -EFAULT;
-	if (tl && copy_to_user(A(n32.object_name), n.object_name, tl))
-		goto out;
-
-	n32.auth_type = n.auth_type;
-	n32.object_name_len = n.object_name_len;
-	
-	if (copy_to_user((struct ncp_objectname_ioctl_32*)arg, &n32, sizeof(n32)))
-		goto out;
-	
-	err = 0;
- out:
- 	if (n.object_name)
-		kfree(n.object_name);
-
-	return err;
-}
-
-static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_objectname_ioctl_32 n32;
-	struct ncp_objectname_ioctl n;
-	mm_segment_t old_fs;
-	int err;
-	size_t tl;
-
-	if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.auth_type = n32.auth_type;
-	n.object_name_len = tl = n32.object_name_len;
-	if (tl) {
-		n.object_name = kmalloc(tl, GFP_KERNEL);
-		if (!n.object_name)
-			return -ENOMEM;
-		err = -EFAULT;
-		if (copy_from_user(n.object_name, A(n32.object_name), tl))
-			goto out;
-	} else {
-		n.object_name = NULL;
-	}
-	
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_SETOBJECTNAME, (unsigned long)&n);
-	set_fs (old_fs);
-		
- out:
-	if (n.object_name)
-		kfree(n.object_name);
-
-	return err;
-}
-
-static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_privatedata_ioctl_32 n32;
-	struct ncp_privatedata_ioctl n;
-	mm_segment_t old_fs;
-	int err;
-	size_t tl;
-
-	if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.len = tl = n32.len;
-	if (tl) {
-		n.data = kmalloc(tl, GFP_KERNEL);
-		if (!n.data)
-			return -ENOMEM;
-	} else {
-		n.data = NULL;
-	}
-
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)&n);
-	set_fs (old_fs);
-        if(err)
-		goto out;
-		
-	if (tl > n.len)
-		tl = n.len;
-
-	err = -EFAULT;
-	if (tl && copy_to_user(A(n32.data), n.data, tl))
-		goto out;
-
-	n32.len = n.len;
-	
-	if (copy_to_user((struct ncp_privatedata_ioctl_32*)arg, &n32, sizeof(n32)))
-		goto out;
-	
-	err = 0;
- out:
- 	if (n.data)
-		kfree(n.data);
-
-	return err;
-}
-
-static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct ncp_privatedata_ioctl_32 n32;
-	struct ncp_privatedata_ioctl n;
-	mm_segment_t old_fs;
-	int err;
-	size_t tl;
-
-	if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
-	    sizeof(n32)))
-		return -EFAULT;
-
-	n.len = tl = n32.len;
-	if (tl) {
-		n.data = kmalloc(tl, GFP_KERNEL);
-		if (!n.data)
-			return -ENOMEM;
-		err = -EFAULT;
-		if (copy_from_user(n.data, A(n32.data), tl))
-			goto out;
-	} else {
-		n.data = NULL;
-	}
-	
-	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)&n);
-	set_fs (old_fs);
-		
- out:
-	if (n.data)
-		kfree(n.data);
-
-	return err;
-}
-
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
 /* This really belongs in include/linux/drm.h -DaveM */
 #include "../../../drivers/char/drm/drm.h"
@@ -1070,18 +770,6 @@
 COMPATIBLE_IOCTL(AUDIO_GETDEV_SUNOS)
 COMPATIBLE_IOCTL(AUDIO_FLUSH)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
-/* NCP ioctls which do not need any translations */
-COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN)
-COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT)
-COMPATIBLE_IOCTL(NCP_IOC_SIGN_WANTED)
-COMPATIBLE_IOCTL(NCP_IOC_SET_SIGN_WANTED)
-COMPATIBLE_IOCTL(NCP_IOC_LOCKUNLOCK)
-COMPATIBLE_IOCTL(NCP_IOC_GETROOT)
-COMPATIBLE_IOCTL(NCP_IOC_SETROOT)
-COMPATIBLE_IOCTL(NCP_IOC_GETCHARSETS)
-COMPATIBLE_IOCTL(NCP_IOC_SETCHARSETS)
-COMPATIBLE_IOCTL(NCP_IOC_GETDENTRYTTL)
-COMPATIBLE_IOCTL(NCP_IOC_SETDENTRYTTL)
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
 COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
 COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
@@ -1107,14 +795,6 @@
 COMPATIBLE_IOCTL(WIOCSTOP)
 COMPATIBLE_IOCTL(WIOCGSTAT)
 /* And these ioctls need translation */
-/* NCPFS */
-HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest)
-HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2)
-HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2)
-HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname)
-HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname)
-HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata)
-HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
 HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap)
 HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap)
--- diff/arch/sparc64/kernel/setup.c	2004-05-19 22:11:24.000000000 +0100
+++ source/arch/sparc64/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -451,8 +451,7 @@
 
 extern int root_mountflags;
 
-char saved_command_line[256];
-char reboot_command[256];
+char reboot_command[COMMAND_LINE_SIZE];
 
 static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
 
--- diff/arch/sparc64/kernel/sparc64_ksyms.c	2004-05-19 22:11:24.000000000 +0100
+++ source/arch/sparc64/kernel/sparc64_ksyms.c	2004-05-27 18:34:15.000000000 +0100
@@ -24,6 +24,7 @@
 #include <linux/socket.h>
 #include <linux/syscalls.h>
 #include <linux/percpu.h>
+#include <linux/init.h>
 #include <net/compat.h>
 
 #include <asm/oplib.h>
@@ -76,7 +77,6 @@
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 extern __kernel_size_t __strlen(const char *);
 extern __kernel_size_t strlen(const char *);
-extern char saved_command_line[];
 extern void linux_sparc_syscall(void);
 extern void rtrap(void);
 extern void show_regs(struct pt_regs *);
--- diff/arch/sparc64/lib/rwlock.S	2004-05-19 22:11:25.000000000 +0100
+++ source/arch/sparc64/lib/rwlock.S	2004-05-27 18:34:15.000000000 +0100
@@ -85,5 +85,20 @@
 __write_trylock_fail:
 	retl
 	 mov		0, %o0
+
+	.globl	__read_trylock
+__read_trylock: /* %o0 = lock_ptr */
+	ldsw		[%o0], %g5
+	brlz,pn		%g5, 100f
+	add		%g5, 1, %g7
+	cas		[%o0], %g5, %g7
+	cmp		%g5, %g7
+	bne,pn		%icc, __read_trylock
+	 membar		#StoreLoad | #StoreStore
+	retl
+	mov		1, %o0
+100:	retl
+	mov		0, %o0
+
 rwlock_impl_end:
 
--- diff/arch/um/kernel/init_task.c	2004-05-19 22:11:27.000000000 +0100
+++ source/arch/um/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -9,6 +9,7 @@
 #include "linux/sched.h"
 #include "linux/init_task.h"
 #include "linux/version.h"
+#include "linux/mqueue.h"
 #include "asm/uaccess.h"
 #include "asm/pgtable.h"
 #include "user_util.h"
--- diff/arch/um/kernel/user_util.c	2004-05-19 22:11:27.000000000 +0100
+++ source/arch/um/kernel/user_util.c	2004-05-27 18:34:15.000000000 +0100
@@ -34,7 +34,6 @@
 #define COMMAND_LINE_SIZE _POSIX_ARG_MAX
 
 /* Changed in linux_main and setup_arch, which run before SMP is started */
-char saved_command_line[COMMAND_LINE_SIZE] = { 0 };
 char command_line[COMMAND_LINE_SIZE] = { 0 };
 
 void add_arg(char *cmd_line, char *arg)
--- diff/arch/v850/kernel/init_task.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/v850/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/v850/kernel/setup.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/v850/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -20,6 +20,7 @@
 #include <linux/major.h>
 #include <linux/root_dev.h>
 #include <linux/mtd/mtd.h>
+#include <linux/init.h>
 
 #include <asm/irq.h>
 
@@ -40,8 +41,7 @@
 extern char _root_fs_image_end __attribute__ ((__weak__));
 
 
-char command_line[512];
-char saved_command_line[512];
+char command_line[COMMAND_LINE_SIZE];
 
 /* Memory not used by the kernel.  */
 static unsigned long total_ram_pages;
--- diff/arch/x86_64/Kconfig	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/x86_64/Kconfig	2004-05-27 18:34:15.000000000 +0100
@@ -455,12 +455,26 @@
 config DEBUG_INFO
 	bool "Compile the kernel with debug info"
 	depends on DEBUG_KERNEL
+	default n
 	help
           If you say Y here the resulting kernel image will include
 	  debugging info resulting in a larger kernel image.
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  Please note that this option requires new binutils.
 	  If you don't debug the kernel, you can say N.
+
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
 	  
 config FRAME_POINTER
        bool "Compile the kernel with frame pointers"
@@ -493,9 +507,8 @@
        help
          Add a simple leak tracer to the IOMMU code. This is useful when you
 	 are debugging a buggy device driver that leaks IOMMU mappings.
-       
-#config X86_REMOTE_DEBUG
-#       bool "kgdb debugging stub"
+
+source "arch/x86_64/Kconfig.kgdb"
 
 endmenu
 
--- diff/arch/x86_64/kernel/Makefile	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/x86_64/kernel/Makefile	2004-05-27 18:34:15.000000000 +0100
@@ -28,6 +28,7 @@
 obj-$(CONFIG_SCHED_SMT)		+= domain.o
 
 obj-$(CONFIG_MODULES)		+= module.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 
 obj-y				+= topology.o
 
--- diff/arch/x86_64/kernel/e820.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/x86_64/kernel/e820.c	2004-05-27 18:34:15.000000000 +0100
@@ -34,7 +34,7 @@
  */
 unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;  
 
-extern struct resource code_resource, data_resource, vram_resource;
+extern struct resource code_resource, data_resource;
 
 /* Check for some hardcoded bad areas that early boot is not allowed to touch */ 
 static inline int bad_addr(unsigned long *addrp, unsigned long size)
--- diff/arch/x86_64/kernel/init_task.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/x86_64/kernel/init_task.c	2004-05-27 18:34:15.000000000 +0100
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/x86_64/kernel/irq.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/x86_64/kernel/irq.c	2004-05-27 18:34:15.000000000 +0100
@@ -405,6 +405,9 @@
 	spin_unlock(&desc->lock);
 
 	irq_exit();
+
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
--- diff/arch/x86_64/kernel/mpparse.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/x86_64/kernel/mpparse.c	2004-05-27 18:34:15.000000000 +0100
@@ -884,91 +884,54 @@
 	return;
 }
 
-
-extern FADT_DESCRIPTOR acpi_fadt;
-
-#ifdef CONFIG_ACPI_PCI
-
-void __init mp_parse_prt (void)
+void mp_register_gsi (u32 gsi, int edge_level, int active_high_low)
 {
-	struct list_head	*node = NULL;
-	struct acpi_prt_entry	*entry = NULL;
 	int			ioapic = -1;
 	int			ioapic_pin = 0;
-	int			gsi = 0;
 	int			idx, bit = 0;
-	int			edge_level = 0;
-	int			active_high_low = 0;
 
-	/*
-	 * Parsing through the PCI Interrupt Routing Table (PRT) and program
-	 * routing for all static (IOAPIC-direct) entries.
-	 */
-	list_for_each(node, &acpi_prt.entries) {
-		entry = list_entry(node, struct acpi_prt_entry, node);
+	if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
+		return;
 
-		/* Need to get gsi for dynamic entry */
-		if (entry->link.handle) {
-			gsi = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
-			if (!gsi)
-				continue;
-		} else {
-			/* Hardwired GSI. Assume PCI standard settings */
-			gsi = entry->link.index;
-			edge_level = 1;
-			active_high_low = 1;
-		}
-
-		/* Don't set up the ACPI SCI because it's already set up */
-		if (acpi_fadt.sci_int == gsi) {
-			/* we still need to set up the entry's irq */
-			acpi_gsi_to_irq(gsi, &entry->irq);
-			continue;
-		}
-
-		ioapic = mp_find_ioapic(gsi);
-		if (ioapic < 0)
-			continue;
-		ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
-
-		/* 
-		 * Avoid pin reprogramming.  PRTs typically include entries  
-		 * with redundant pin->gsi mappings (but unique PCI devices);
-		 * we only only program the IOAPIC on the first.
-		 */
-		bit = ioapic_pin % 32;
-		idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
-		if (idx > 3) {
-			printk(KERN_ERR "Invalid reference to IOAPIC pin "
-				"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
-				ioapic_pin);
-			continue;
-		}
-		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
-			Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
-				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
-			acpi_gsi_to_irq(gsi, &entry->irq);
-			continue;
-		}
-
-		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
-		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
-			acpi_gsi_to_irq(gsi, &entry->irq);
- 		}
-		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
-			entry->id.segment, entry->id.bus,
-			entry->id.device, ('A' + entry->pin), 
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
-			entry->irq);
+#ifdef CONFIG_ACPI_BUS
+	/* Don't set up the ACPI SCI because it's already set up */
+	if (acpi_fadt.sci_int == gsi)
+		return;
+#endif
+
+	ioapic = mp_find_ioapic(gsi);
+	if (ioapic < 0) {
+		printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
+		return;
 	}
-	
-	print_IO_APIC();
 
-	return;
-}
+	ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
 
-#endif /*CONFIG_ACPI_PCI*/
+	/* 
+	 * Avoid pin reprogramming.  PRTs typically include entries  
+	 * with redundant pin->gsi mappings (but unique PCI devices);
+	 * we only program the IOAPIC on the first.
+	 */
+	bit = ioapic_pin % 32;
+	idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
+	if (idx > 3) {
+		printk(KERN_ERR "Invalid reference to IOAPIC pin "
+			"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
+			ioapic_pin);
+		return;
+	}
+	if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+		Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
+			mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+		return;
+	}
 
-#endif /*CONFIG_X86_IO_APIC*/
+	mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
 
+	io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
+		edge_level == ACPI_EDGE_SENSITIVE ? 0 : 1,
+		active_high_low == ACPI_ACTIVE_HIGH ? 0 : 1);
+}
+
+#endif /*CONFIG_X86_IO_APIC*/
 #endif /*CONFIG_ACPI_BOOT*/
--- diff/arch/x86_64/kernel/setup.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/x86_64/kernel/setup.c	2004-05-27 18:34:15.000000000 +0100
@@ -100,7 +100,6 @@
 extern char _text, _etext, _edata, _end;
 
 char command_line[COMMAND_LINE_SIZE];
-char saved_command_line[COMMAND_LINE_SIZE];
 
 struct resource standard_io_resources[] = {
 	{ "dma1", 0x00, 0x1f, IORESOURCE_BUSY | IORESOURCE_IO },
@@ -116,9 +115,10 @@
 #define STANDARD_IO_RESOURCES \
 	(sizeof standard_io_resources / sizeof standard_io_resources[0])
 
-struct resource code_resource = { "Kernel code", 0x100000, 0, IORESOURCE_MEM };
-struct resource data_resource = { "Kernel data", 0, 0, IORESOURCE_MEM };
-struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY | IORESOURCE_MEM };
+#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
+
+struct resource data_resource = { "Kernel data", 0, 0, IORESOURCE_RAM };
+struct resource code_resource = { "Kernel code", 0, 0, IORESOURCE_RAM };
 
 #define IORESOURCE_ROM (IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM)
 
@@ -138,10 +138,11 @@
 	(sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
 
 static struct resource video_rom_resource = { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_ROM };
+static struct resource video_ram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_RAM };
 
 #define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
 
-static int __init checksum(unsigned char *rom, unsigned long length)
+static int __init romchecksum(unsigned char *rom, unsigned long length)
 {
 	unsigned char *p, sum = 0;
 
@@ -169,7 +170,7 @@
 		length = rom[2] * 512;
 
 		/* if checksum okay, trust length byte */
-		if (length && checksum(rom, length))
+		if (length && romchecksum(rom, length))
 			video_rom_resource.end = start + length - 1;
 
 		request_resource(&iomem_resource, &video_rom_resource);
@@ -188,7 +189,7 @@
 	rom = isa_bus_to_virt(extension_rom_resource.start);
 	if (romsignature(rom)) {
 		length = extension_rom_resource.end - extension_rom_resource.start + 1;
-		if (checksum(rom, length)) {
+		if (romchecksum(rom, length)) {
 			request_resource(&iomem_resource, &extension_rom_resource);
 			upper = extension_rom_resource.start;
 		}
@@ -204,7 +205,7 @@
 		length = rom[2] * 512;
 
 		/* but accept any length that fits if checksum okay */
-		if (!length || start + length > upper || !checksum(rom, length))
+		if (!length || start + length > upper || !romchecksum(rom, length))
 			continue;
 
 		adapter_rom_resources[i].start = start;
@@ -554,13 +555,13 @@
 	probe_roms();
 	e820_reserve_resources(); 
 
-	request_resource(&iomem_resource, &vram_resource);
+	request_resource(&iomem_resource, &video_ram_resource);
 
 	{
 	unsigned i;
 	/* request I/O space for devices used on all i[345]86 PCs */
 	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
-		request_resource(&ioport_resource, standard_io_resources+i);
+		request_resource(&ioport_resource, &standard_io_resources[i]);
 	}
 
 	/* Will likely break when you have unassigned resources with more
--- diff/arch/x86_64/kernel/smp.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/x86_64/kernel/smp.c	2004-05-27 18:34:15.000000000 +0100
@@ -362,6 +362,18 @@
 	send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
 }
 
+#ifdef CONFIG_KGDB
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+void smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
+
 /*
  * Structure and data for smp_call_function(). This is designed to minimise
  * static memory requirements. It also looks cleaner.
--- diff/arch/x86_64/kernel/traps.c	2004-05-27 13:41:16.000000000 +0100
+++ source/arch/x86_64/kernel/traps.c	2004-05-27 18:34:15.000000000 +0100
@@ -45,6 +45,9 @@
 #include <asm/proto.h>
 
 #include <linux/irq.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
 
 extern struct gate_struct idt_table[256]; 
 
--- diff/arch/x86_64/lib/Makefile	2004-05-19 22:11:29.000000000 +0100
+++ source/arch/x86_64/lib/Makefile	2004-05-27 18:34:15.000000000 +0100
@@ -10,3 +10,4 @@
 lib-y += memcpy.o memmove.o memset.o copy_user.o
 
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB) += kgdb_serial.o
--- diff/crypto/cipher.c	2004-05-19 22:11:29.000000000 +0100
+++ source/crypto/cipher.c	2004-05-27 18:34:15.000000000 +0100
@@ -68,19 +68,20 @@
 
 	for(;;) {
 		u8 *src_p, *dst_p;
+		int in_place;
 
 		scatterwalk_map(&walk_in, 0);
 		scatterwalk_map(&walk_out, 1);
 		src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src);
 		dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst);
+		in_place = scatterwalk_samebuf(&walk_in, &walk_out,
+					       src_p, dst_p);
 
 		nbytes -= bsize;
 
 		scatterwalk_copychunks(src_p, &walk_in, bsize, 0);
 
-		prfn(tfm, dst_p, src_p, crfn, enc, info,
-		     scatterwalk_samebuf(&walk_in, &walk_out,
-					 src_p, dst_p));
+		prfn(tfm, dst_p, src_p, crfn, enc, info, in_place);
 
 		scatterwalk_done(&walk_in, 0, nbytes);
 
--- diff/crypto/scatterwalk.h	2004-05-19 22:11:29.000000000 +0100
+++ source/crypto/scatterwalk.h	2004-05-27 18:34:15.000000000 +0100
@@ -38,6 +38,7 @@
 				      void *src_p, void *dst_p)
 {
 	return walk_in->page == walk_out->page &&
+	       walk_in->offset == walk_out->offset &&
 	       walk_in->data == src_p && walk_out->data == dst_p;
 }
 
--- diff/drivers/acpi/Kconfig	2004-05-19 22:11:29.000000000 +0100
+++ source/drivers/acpi/Kconfig	2004-05-27 18:34:15.000000000 +0100
@@ -267,7 +267,7 @@
 	  (TSC) timing source.
 
 	  So, if you see messages like 'Losing too many ticks!' in the
-	  kernel logs, and/or you are using a this on a notebook which
+	  kernel logs, and/or you are using this on a notebook which
 	  does not yet have an HPET, you should say "Y" here.
 
 endmenu
--- diff/drivers/acpi/pci_irq.c	2004-05-19 22:11:29.000000000 +0100
+++ source/drivers/acpi/pci_irq.c	2004-05-27 18:34:15.000000000 +0100
@@ -35,12 +35,6 @@
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
-#ifdef CONFIG_X86_IO_APIC
-#include <asm/mpspec.h>
-#endif
-#ifdef CONFIG_IOSAPIC
-# include <asm/iosapic.h>
-#endif
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -50,10 +44,6 @@
 
 struct acpi_prt_list		acpi_prt;
 
-#ifdef CONFIG_X86
-extern void eisa_set_level_irq(unsigned int irq);
-#endif
-
 
 /* --------------------------------------------------------------------------
                          PCI IRQ Routing Table (PRT) Support
@@ -237,12 +227,18 @@
                           PCI Interrupt Routing Support
    -------------------------------------------------------------------------- */
 
-int
-acpi_pci_irq_lookup (struct pci_bus *bus, int device, int pin)
+static int
+acpi_pci_irq_lookup (
+	struct pci_bus		*bus,
+	int			device,
+	int			pin,
+	int			*edge_level,
+	int			*active_high_low)
 {
 	struct acpi_prt_entry	*entry = NULL;
 	int segment = pci_domain_nr(bus);
 	int bus_nr = bus->number;
+	int irq;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
 
@@ -255,28 +251,30 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n"));
 		return_VALUE(0);
 	}
-
-	if (!entry->irq && entry->link.handle) {
-		entry->irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, NULL, NULL);
-		if (!entry->irq) {
+	
+	if (entry->link.handle) {
+		irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, edge_level, active_high_low);
+		if (!irq) {
 			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
 			return_VALUE(0);
 		}
-	}
-	else if (!entry->irq) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid static routing entry (IRQ 0)\n"));
-		return_VALUE(0);
+	} else {
+		irq = entry->link.index;
+		*edge_level = ACPI_LEVEL_SENSITIVE;
+		*active_high_low = ACPI_ACTIVE_LOW;
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", entry->irq));
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
 
-	return_VALUE(entry->irq);
+	return_VALUE(irq);
 }
 
 static int
 acpi_pci_irq_derive (
 	struct pci_dev		*dev,
-	int			pin)
+	int			pin,
+	int			*edge_level,
+	int			*active_high_low)
 {
 	struct pci_dev		*bridge = dev;
 	int			irq = 0;
@@ -308,8 +306,8 @@
 			pin = bridge_pin;
 		}
 
-		irq = acpi_pci_irq_lookup(bridge->bus,
-				PCI_SLOT(bridge->devfn), pin);
+		irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
+			pin, edge_level, active_high_low);
 	}
 
 	if (!irq) {
@@ -330,6 +328,8 @@
 {
 	int			irq = 0;
 	u8			pin = 0;
+	int			edge_level = ACPI_LEVEL_SENSITIVE;
+	int			active_high_low = ACPI_ACTIVE_LOW;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
 
@@ -352,21 +352,22 @@
 	 * First we check the PCI IRQ routing table (PRT) for an IRQ.  PRT
 	 * values override any BIOS-assigned IRQs set during boot.
 	 */
- 	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin);
+ 	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, &edge_level, &active_high_low);
 
 	/*
 	 * If no PRT entry was found, we'll try to derive an IRQ from the
 	 * device's parent bridge.
 	 */
 	if (!irq)
- 		irq = acpi_pci_irq_derive(dev, pin);
+ 		irq = acpi_pci_irq_derive(dev, pin, &edge_level, &active_high_low);
  
 	/*
 	 * No IRQ known to the ACPI subsystem - maybe the BIOS / 
 	 * driver reported one, then use it. Exit in any case.
 	 */
 	if (!irq) {
-		printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s", ('A' + pin), pci_name(dev));
+		printk(KERN_WARNING PREFIX "PCI interrupt %s[%c]: no GSI",
+			pci_name(dev), ('A' + pin));
 		/* Interrupt Line values above 0xF are forbidden */
 		if (dev->irq && (dev->irq <= 0xF)) {
 			printk(" - using IRQ %d\n", dev->irq);
@@ -378,62 +379,14 @@
 		}
  	}
 
-	dev->irq = irq;
+	dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s using IRQ %d\n", pci_name(dev), dev->irq));
-
-	/* 
-	 * Make sure all (legacy) PCI IRQs are set as level-triggered.
-	 */
-#ifdef CONFIG_X86
-	{
-		static u16 irq_mask;
-		if ((dev->irq < 16) &&  !((1 << dev->irq) & irq_mask)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Setting IRQ %d as level-triggered\n", dev->irq));
-			irq_mask |= (1 << dev->irq);
-			eisa_set_level_irq(dev->irq);
-		}
-	}
-#endif
-#ifdef CONFIG_IOSAPIC
-	if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
-		iosapic_enable_intr(dev->irq);
-#endif
+	printk(KERN_INFO PREFIX "PCI interrupt %s[%c] -> GSI %u "
+		"(%s, %s) -> IRQ %d\n",
+		pci_name(dev), 'A' + pin, irq,
+		(edge_level == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
+		(active_high_low == ACPI_ACTIVE_LOW) ? "low" : "high",
+		dev->irq);
 
 	return_VALUE(dev->irq);
 }
-
-
-int __init
-acpi_pci_irq_init (void)
-{
-	struct pci_dev          *dev = NULL;
-
-	ACPI_FUNCTION_TRACE("acpi_pci_irq_init");
-
-	if (!acpi_prt.count) {
-		printk(KERN_WARNING PREFIX "ACPI tables contain no PCI IRQ "
-			"routing entries\n");
-		return_VALUE(-ENODEV);
-	}
-
-	/* Make sure all link devices have a valid IRQ. */
-	if (acpi_pci_link_check()) {
-		return_VALUE(-ENODEV);
-	}
-
-#ifdef CONFIG_X86_IO_APIC
-	/* Program IOAPICs using data from PRT entries. */
-	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
-		mp_parse_prt();
-#endif
-#ifdef CONFIG_IOSAPIC
-	if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
-		iosapic_parse_prt();
-#endif
-
-	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
-		acpi_pci_irq_enable(dev);
-
-	return_VALUE(0);
-}
--- diff/drivers/acpi/pci_link.c	2004-05-27 13:41:16.000000000 +0100
+++ source/drivers/acpi/pci_link.c	2004-05-27 18:34:15.000000000 +0100
@@ -487,13 +487,13 @@
 };
 
 int
-acpi_pci_link_check (void)
+acpi_irq_penalty_init(void)
 {
 	struct list_head	*node = NULL;
 	struct acpi_pci_link    *link = NULL;
 	int			i = 0;
 
-	ACPI_FUNCTION_TRACE("acpi_pci_link_check");
+	ACPI_FUNCTION_TRACE("acpi_irq_penalty_init");
 
 	/*
 	 * Update penalties to facilitate IRQ balancing.
--- diff/drivers/acpi/tables.c	2004-05-27 13:41:16.000000000 +0100
+++ source/drivers/acpi/tables.c	2004-05-27 18:34:15.000000000 +0100
@@ -131,7 +131,7 @@
 	{
 		struct acpi_table_ioapic *p =
 			(struct acpi_table_ioapic*) header;
-		printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] global_irq_base[0x%x])\n",
+		printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
 			p->id, p->address, p->global_irq_base);
 	}
 		break;
@@ -185,8 +185,8 @@
 	{
 		struct acpi_table_iosapic *p =
 			(struct acpi_table_iosapic*) header;
-		printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] global_irq_base[0x%x] address[%p])\n",
-			p->id, p->global_irq_base, (void *) (unsigned long) p->address);
+		printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
+			p->id, (void *) (unsigned long) p->address, p->global_irq_base);
 	}
 		break;
 
--- diff/drivers/atm/firestream.c	2004-05-19 22:11:30.000000000 +0100
+++ source/drivers/atm/firestream.c	2004-05-27 18:34:15.000000000 +0100
@@ -576,7 +576,7 @@
 }
 
 
-static inline u32  read_fs (struct fs_dev *dev, int offset)
+static inline u32 read_fs (struct fs_dev *dev, int offset)
 {
 	return readl (dev->base + offset);
 }
@@ -1380,7 +1380,7 @@
 
 	if (alignment <= 0x10) {
 		t = kmalloc (size, flags);
-		if ((unsigned int)t & (alignment-1)) {
+		if ((unsigned long)t & (alignment-1)) {
 			printk ("Kmalloc doesn't align things correctly! %p\n", t);
 			kfree (t);
 			return aligned_kmalloc (size, flags, alignment * 4);
@@ -1496,7 +1496,7 @@
 		ne->skb = skb;
 		ne->fp = fp;
 
-		qe = (struct FS_BPENTRY *) (read_fs (dev, FP_EA(fp->offset)));
+		qe = (struct FS_BPENTRY *)(long)(read_fs (dev, FP_EA(fp->offset)));
 		fs_dprintk (FS_DEBUG_QUEUE, "link at %p\n", qe);
 		if (qe) {
 			qe = bus_to_virt ((long) qe);
--- diff/drivers/base/power/resume.c	2004-05-19 22:11:32.000000000 +0100
+++ source/drivers/base/power/resume.c	2004-05-27 18:34:15.000000000 +0100
@@ -35,7 +35,10 @@
 		struct list_head * entry = dpm_off.next;
 		struct device * dev = to_device(entry);
 		list_del_init(entry);
-		resume_device(dev);
+
+		if (!dev->power.power_state)
+			resume_device(dev);
+
 		list_add_tail(entry,&dpm_active);
 	}
 }
--- diff/drivers/base/power/runtime.c	2004-05-19 22:11:32.000000000 +0100
+++ source/drivers/base/power/runtime.c	2004-05-27 18:34:15.000000000 +0100
@@ -14,7 +14,10 @@
 {
 	if (!dev->power.power_state)
 		return;
-	resume_device(dev);
+	if (! resume_device(dev))
+		dev->power.power_state = 0;
+
+	return;
 }
 
 
--- diff/drivers/base/power/suspend.c	2004-05-19 22:11:32.000000000 +0100
+++ source/drivers/base/power/suspend.c	2004-05-27 18:34:15.000000000 +0100
@@ -39,16 +39,9 @@
 {
 	int error = 0;
 
-	if (dev->bus && dev->bus->suspend)
+	if (dev->bus && dev->bus->suspend && !dev->power.power_state)
 		error = dev->bus->suspend(dev,state);
 
-	if (!error) {
-		list_del(&dev->power.entry);
-		list_add(&dev->power.entry,&dpm_off);
-	} else if (error == -EAGAIN) {
-		list_del(&dev->power.entry);
-		list_add(&dev->power.entry,&dpm_off_irq);
-	}
 	return error;
 }
 
@@ -81,12 +74,16 @@
 	while(!list_empty(&dpm_active)) {
 		struct list_head * entry = dpm_active.prev;
 		struct device * dev = to_device(entry);
-		if ((error = suspend_device(dev,state))) {
-			if (error != -EAGAIN)
-				goto Error;
-			else
-				error = 0;
-		}
+		error = suspend_device(dev,state);
+
+		if (!error) {
+			list_del(&dev->power.entry);
+			list_add(&dev->power.entry,&dpm_off);
+		} else if (error == -EAGAIN) {
+			list_del(&dev->power.entry);
+			list_add(&dev->power.entry,&dpm_off_irq);
+		} else
+			goto Error;
 	}
  Done:
 	up(&dpm_sem);
--- diff/drivers/block/Kconfig	2004-05-27 13:41:16.000000000 +0100
+++ source/drivers/block/Kconfig	2004-05-27 18:34:15.000000000 +0100
@@ -6,7 +6,7 @@
 
 config BLK_DEV_FD
 	tristate "Normal floppy disk support"
-	depends on (!X86_PC9800 && !ARCH_S390 && !M68K && !IA64) || Q40 || (SUN3X && BROKEN)
+	depends on (!ARCH_S390 && !M68K && !IA64) || Q40 || (SUN3X && BROKEN)
 	---help---
 	  If you want to use the floppy disk drive(s) of your PC under Linux,
 	  say Y. Information about this driver, especially important for IBM
@@ -26,13 +26,6 @@
 	tristate "Atari floppy support"
 	depends on ATARI
 
-config BLK_DEV_FD98
-	tristate "NEC PC-9800 floppy disk support"
-	depends on X86_PC9800
-	---help---
-	  If you want to use the floppy disk drive(s) of NEC PC-9801/PC-9821,
-	  say Y.
-
 config BLK_DEV_SWIM_IOP
 	bool "Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)"
 	depends on MAC && EXPERIMENTAL && BROKEN
--- diff/drivers/block/ll_rw_blk.c	2004-05-27 13:41:16.000000000 +0100
+++ source/drivers/block/ll_rw_blk.c	2004-05-27 18:34:15.000000000 +0100
@@ -106,22 +106,28 @@
 	q->nr_congestion_off = nr;
 }
 
-/*
- * A queue has just exitted congestion.  Note this in the global counter of
- * congested queues, and wake up anyone who was waiting for requests to be
- * put back.
- */
-static void clear_queue_congested(request_queue_t *q, int rw)
+void clear_backing_dev_congested(struct backing_dev_info *bdi, int rw)
 {
 	enum bdi_state bit;
 	wait_queue_head_t *wqh = &congestion_wqh[rw];
 
 	bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
-	clear_bit(bit, &q->backing_dev_info.state);
+	clear_bit(bit, &bdi->state);
 	smp_mb__after_clear_bit();
 	if (waitqueue_active(wqh))
 		wake_up(wqh);
 }
+EXPORT_SYMBOL(clear_backing_dev_congested);
+
+/*
+ * A queue has just exitted congestion.  Note this in the global counter of
+ * congested queues, and wake up anyone who was waiting for requests to be
+ * put back.
+ */
+static void clear_queue_congested(request_queue_t *q, int rw)
+{
+	clear_backing_dev_congested(&q->backing_dev_info, rw);
+}
 
 /*
  * A queue has just entered congestion.  Flag that in the queue's VM-visible
@@ -263,6 +269,45 @@
 EXPORT_SYMBOL(blk_queue_make_request);
 
 /**
+ * blk_queue_ordered - does this queue support ordered writes
+ * @q:     the request queue
+ * @flag:  see below
+ *
+ * Description:
+ *   For journalled file systems, doing ordered writes on a commit
+ *   block instead of explicitly doing wait_on_buffer (which is bad
+ *   for performance) can be a big win. Block drivers supporting this
+ *   feature should call this function and indicate so.
+ *
+ **/
+void blk_queue_ordered(request_queue_t *q, int flag)
+{
+	if (flag)
+		set_bit(QUEUE_FLAG_ORDERED, &q->queue_flags);
+	else
+		clear_bit(QUEUE_FLAG_ORDERED, &q->queue_flags);
+}
+
+EXPORT_SYMBOL(blk_queue_ordered);
+
+/**
+ * blk_queue_issue_flush_fn - set function for issuing a flush
+ * @q:     the request queue
+ * @iff:   the function to be called issuing the flush
+ *
+ * Description:
+ *   If a driver supports issuing a flush command, the support is notified
+ *   to the block layer by defining it through this call.
+ *
+ **/
+void blk_queue_issue_flush_fn(request_queue_t *q, issue_flush_fn *iff)
+{
+	q->issue_flush_fn = iff;
+}
+
+EXPORT_SYMBOL(blk_queue_issue_flush_fn);
+
+/**
  * blk_queue_bounce_limit - set bounce buffer limit for queue
  * @q:  the request queue for the device
  * @dma_addr:   bus address limit
@@ -1151,6 +1196,7 @@
  **/
 void generic_unplug_device(request_queue_t *q)
 {
+	might_sleep();
 	spin_lock_irq(q->queue_lock);
 	__generic_unplug_device(q);
 	spin_unlock_irq(q->queue_lock);
@@ -1872,10 +1918,11 @@
 	}
 
 	rq->flags |= REQ_NOMERGE;
-	rq->waiting = &wait;
+	if (!rq->waiting)
+		rq->waiting = &wait;
 	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
 	generic_unplug_device(q);
-	wait_for_completion(&wait);
+	wait_for_completion(rq->waiting);
 	rq->waiting = NULL;
 
 	if (rq->errors)
@@ -1886,6 +1933,72 @@
 
 EXPORT_SYMBOL(blk_execute_rq);
 
+/**
+ * blkdev_issue_flush - queue a flush
+ * @bdev:	blockdev to issue flush for
+ * @error_sector:	error sector
+ *
+ * Description:
+ *    Issue a flush for the block device in question. Caller can supply
+ *    room for storing the error offset in case of a flush error, if they
+ *    wish to.  Caller must run wait_for_completion() on its own.
+ */
+int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector)
+{
+	request_queue_t *q;
+
+	if (bdev->bd_disk == NULL)
+		return -ENXIO;
+
+	q = bdev_get_queue(bdev);
+	if (!q)
+		return -ENXIO;
+	if (!q->issue_flush_fn)
+		return -EOPNOTSUPP;
+
+	return q->issue_flush_fn(q, bdev->bd_disk, error_sector);
+}
+
+EXPORT_SYMBOL(blkdev_issue_flush);
+
+/**
+ * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices
+ * @q:		device queue
+ * @disk:	gendisk
+ * @error_sector:	error offset
+ *
+ * Description:
+ *    Devices understanding the SCSI command set, can use this function as
+ *    a helper for issuing a cache flush. Note: driver is required to store
+ *    the error offset (in case of error flushing) in ->sector of struct
+ *    request.
+ */
+int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
+			       sector_t *error_sector)
+{
+	struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT);
+	int ret;
+
+	rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+	rq->sector = 0;
+	memset(rq->cmd, 0, sizeof(rq->cmd));
+	rq->cmd[0] = 0x35;
+	rq->cmd_len = 12;
+	rq->data = NULL;
+	rq->data_len = 0;
+	rq->timeout = 60 * HZ;
+
+	ret = blk_execute_rq(q, disk, rq);
+
+	if (ret && error_sector)
+		*error_sector = rq->sector;
+
+	blk_put_request(rq);
+	return ret;
+}
+
+EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn);
+
 void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
 {
 	int rw = rq_data_dir(rq);
@@ -2139,7 +2252,7 @@
 static int __make_request(request_queue_t *q, struct bio *bio)
 {
 	struct request *req, *freereq = NULL;
-	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, ra;
+	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err;
 	sector_t sector;
 
 	sector = bio->bi_sector;
@@ -2157,9 +2270,11 @@
 
 	spin_lock_prefetch(q->queue_lock);
 
-	barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw);
-
-	ra = bio->bi_rw & (1 << BIO_RW_AHEAD);
+	barrier = bio_barrier(bio);
+	if (barrier && !(q->queue_flags & (1 << QUEUE_FLAG_ORDERED))) {
+		err = -EOPNOTSUPP;
+		goto end_io;
+	}
 
 again:
 	spin_lock_irq(q->queue_lock);
@@ -2239,7 +2354,8 @@
 			/*
 			 * READA bit set
 			 */
-			if (ra)
+			err = -EWOULDBLOCK;
+			if (bio_rw_ahead(bio))
 				goto end_io;
 	
 			freereq = get_request_wait(q, rw);
@@ -2250,10 +2366,9 @@
 	req->flags |= REQ_CMD;
 
 	/*
-	 * inherit FAILFAST from bio and don't stack up
-	 * retries for read ahead
+	 * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST)
 	 */
-	if (ra || test_bit(BIO_RW_FAILFAST, &bio->bi_rw))	
+	if (bio_rw_ahead(bio) || bio_failfast(bio))
 		req->flags |= REQ_FAILFAST;
 
 	/*
@@ -2291,7 +2406,7 @@
 	return 0;
 
 end_io:
-	bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK);
+	bio_endio(bio, nr_sectors << 9, err);
 	return 0;
 }
 
@@ -2591,10 +2706,17 @@
 static int __end_that_request_first(struct request *req, int uptodate,
 				    int nr_bytes)
 {
-	int total_bytes, bio_nbytes, error = 0, next_idx = 0;
+	int total_bytes, bio_nbytes, error, next_idx = 0;
 	struct bio *bio;
 
 	/*
+	 * extend uptodate bool to allow < 0 value to be direct io error
+	 */
+	error = 0;
+	if (end_io_error(uptodate))
+		error = !uptodate ? -EIO : uptodate;
+
+	/*
 	 * for a REQ_BLOCK_PC request, we want to carry any eventual
 	 * sense key with us all the way through
 	 */
@@ -2602,7 +2724,6 @@
 		req->errors = 0;
 
 	if (!uptodate) {
-		error = -EIO;
 		if (blk_fs_request(req) && !(req->flags & REQ_QUIET))
 			printk("end_request: I/O error, dev %s, sector %llu\n",
 				req->rq_disk ? req->rq_disk->disk_name : "?",
@@ -2685,7 +2806,7 @@
 /**
  * end_that_request_first - end I/O on a request
  * @req:      the request being processed
- * @uptodate: 0 for I/O error
+ * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
  * @nr_sectors: number of sectors to end I/O on
  *
  * Description:
@@ -2706,7 +2827,7 @@
 /**
  * end_that_request_chunk - end I/O on a request
  * @req:      the request being processed
- * @uptodate: 0 for I/O error
+ * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
  * @nr_bytes: number of bytes to complete
  *
  * Description:
@@ -2824,19 +2945,13 @@
 		panic("Failed to create kblockd\n");
 
 	request_cachep = kmem_cache_create("blkdev_requests",
-			sizeof(struct request), 0, 0, NULL, NULL);
-	if (!request_cachep)
-		panic("Can't create request pool slab cache\n");
+			sizeof(struct request), 0, SLAB_PANIC, NULL, NULL);
 
 	requestq_cachep = kmem_cache_create("blkdev_queue",
-			sizeof(request_queue_t), 0, 0, NULL, NULL);
-	if (!requestq_cachep)
-		panic("Can't create request queue slab cache\n");
+			sizeof(request_queue_t), 0, SLAB_PANIC, NULL, NULL);
 
 	iocontext_cachep = kmem_cache_create("blkdev_ioc",
-			sizeof(struct io_context), 0, 0, NULL, NULL);
-	if (!iocontext_cachep)
-		panic("Can't create io context slab cache\n");
+			sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL);
 
 	blk_max_low_pfn = max_low_pfn;
 	blk_max_pfn = max_pfn;
--- diff/drivers/block/rd.c	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/block/rd.c	2004-05-27 18:34:15.000000000 +0100
@@ -108,8 +108,21 @@
 		struct buffer_head *head = bh;
 
 		do {
-			if (!buffer_uptodate(bh))
+			if (!buffer_uptodate(bh)) {
 				memset(bh->b_data, 0, bh->b_size);
+				/*
+				 * akpm: I'm totally undecided about this.  The
+				 * buffer has just been magically brought "up to
+				 * date", but nobody should want to be reading
+				 * it anyway, because it hasn't been used for
+				 * anything yet.  It is still in a "not read
+				 * from disk yet" state.
+				 *
+				 * But non-uptodate buffers against an uptodate
+				 * page are against the rules.  So do it anyway.
+				 */
+				 set_buffer_uptodate(bh);
+			}
 		} while ((bh = bh->b_this_page) != head);
 	} else {
 		memset(page_address(page), 0, PAGE_CACHE_SIZE);
--- diff/drivers/block/viodasd.c	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/block/viodasd.c	2004-05-27 18:34:15.000000000 +0100
@@ -40,8 +40,11 @@
 #include <linux/string.h>
 #include <linux/dma-mapping.h>
 #include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
 
 #include <asm/uaccess.h>
+#include <asm/vio.h>
 #include <asm/iSeries/HvTypes.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvLpConfig.h>
@@ -519,13 +522,6 @@
 		       "bad rc sending event to OS/400 %d\n", (int)hvrc);
 		return;
 	}
-	printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) "
-			"CHS=%d/%d/%d sector size %d%s\n",
-			dev_no, (unsigned long)(d->size >> 9),
-			(unsigned long)(d->size >> 20),
-			(int)d->cylinders, (int)d->tracks,
-			(int)d->sectors, (int)d->bytes_per_sector,
-			d->read_only ? " (RO)" : "");
 	/* create the request queue for the disk */
 	spin_lock_init(&d->q_lock);
 	q = blk_init_queue(do_viodasd_request, &d->q_lock);
@@ -563,6 +559,14 @@
 	g->private_data = d;
 	set_capacity(g, d->size >> 9);
 
+	printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) "
+			"CHS=%d/%d/%d sector size %d%s\n",
+			dev_no, (unsigned long)(d->size >> 9),
+			(unsigned long)(d->size >> 20),
+			(int)d->cylinders, (int)d->tracks,
+			(int)d->sectors, (int)d->bytes_per_sector,
+			d->read_only ? " (RO)" : "");
+
 	/* register us in the global list */
 	add_disk(g);
 }
@@ -725,6 +729,26 @@
 }
 
 /*
+ * Get the driver to reprobe for more disks.
+ */
+static ssize_t probe_disks(struct device_driver *drv, const char *buf,
+		size_t count)
+{
+	struct viodasd_device *d;
+
+	for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) {
+		if (d->disk == NULL)
+			probe_disk(d);
+	}
+	return count;
+}
+static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks)
+
+static struct vio_driver viodasd_driver = {
+	.name = "viodasd"
+};
+
+/*
  * Initialize the whole device driver.  Handle module and non-module
  * versions
  */
@@ -767,6 +791,9 @@
 	for (i = 0; i < MAX_DISKNO; i++)
 		probe_disk(&viodasd_devices[i]);
 
+	vio_register_driver(&viodasd_driver);	/* FIX ME - error checking */
+	driver_create_file(&viodasd_driver.driver, &driver_attr_probe);
+
 	return 0;
 }
 module_init(viodasd_init);
@@ -776,6 +803,9 @@
 	int i;
 	struct viodasd_device *d;
 
+	driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
+	vio_unregister_driver(&viodasd_driver);
+
         for (i = 0; i < MAX_DISKNO; i++) {
 		d = &viodasd_devices[i];
 		if (d->disk) {
--- diff/drivers/bluetooth/bt3c_cs.c	2004-05-19 22:11:33.000000000 +0100
+++ source/drivers/bluetooth/bt3c_cs.c	2004-05-27 18:34:15.000000000 +0100
@@ -491,6 +491,9 @@
 
 static struct device bt3c_device = {
 	.bus_id = "pcmcia",
+	.kobj = {
+		.k_name = "bt3c"
+	}
 };
 
 
--- diff/drivers/bluetooth/hci_bcsp.c	2004-05-19 22:11:33.000000000 +0100
+++ source/drivers/bluetooth/hci_bcsp.c	2004-05-27 18:34:15.000000000 +0100
@@ -33,7 +33,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
--- diff/drivers/char/Kconfig	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/char/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -586,17 +586,6 @@
 	  console. This driver allows each pSeries partition to have a console
 	  which is accessed via the HMC.
 
-config PC9800_OLDLP
-	tristate "NEC PC-9800 old-style printer port support"
-	depends on X86_PC9800 && !PARPORT
-	---help---
-	  If you intend to attach a printer to the parallel port of NEC PC-9801
-	  /PC-9821 with OLD compatibility mode, Say Y.
-
-config PC9800_OLDLP_CONSOLE
-	bool "Support for console on line printer"
-	depends on PC9800_OLDLP
-
 config QIC02_TAPE
 	tristate "QIC-02 tape support"
 	help
@@ -740,7 +729,7 @@
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
-	depends on !PPC32 && !PARISC && !IA64 && !X86_PC9800 && !M68K
+	depends on !PPC32 && !PARISC && !IA64 && !M68K
 	---help---
 	  If you say Y here and create a character special file /dev/rtc with
 	  major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -793,15 +782,6 @@
 	bool "EFI Real Time Clock Services"
 	depends on IA64
 
-config RTC98
-	tristate "NEC PC-9800 Real Time Clock Support"
-	depends on X86_PC9800
-	default y
-	---help---
-	  If you say Y here and create a character special file /dev/rtc with
-	  major number 10 and minor number 135 using mknod ("man mknod"), you
-	  will get access to the real time clock (or hardware clock) built
-
 config H8
 	bool "Tadpole ANA H8 Support (OBSOLETE)"
 	depends on OBSOLETE && ALPHA_BOOK1
@@ -957,6 +937,33 @@
           kernels.  Applications should simply open the device (eg /dev/hda1)
           with the O_DIRECT flag.
 
+config HPET
+	bool "HPET - High Precision Event Timer" if (X86 || IA64)
+	default n
+	depends on ACPI
+	help
+	  If you say Y here, you will have a device named "/dev/hpet/XX" for
+	  each timer supported by the HPET.  The timers are
+	  non-periodioc and/or periodic.
+
+config HPET_RTC_IRQ
+	bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC
+	default n
+	depends on HPET
+	help
+	  If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It
+	  is assumed the platform called hpet_alloc with the RTC IRQ values for
+	  the HPET timers.
+
+config HPET_NOMMAP
+	bool "HPET - Control mmap capability."
+	default n
+	depends on HPET
+	help
+	  If you say Y here, then the mmap interface for the HPET driver returns ENOSYS.
+	  Some hardware implementations might not want all the memory in the page the
+	  HPET control registers reside to be exposed.
+
 config MAX_RAW_DEVS
 	int "Maximum number of RAW devices to support (1-8192)"
 	depends on RAW_DRIVER
--- diff/drivers/char/Makefile	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/char/Makefile	2004-05-27 18:34:16.000000000 +0100
@@ -47,13 +47,13 @@
 
 obj-$(CONFIG_PRINTER) += lp.o
 obj-$(CONFIG_TIPAR) += tipar.o
-obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o
 
 obj-$(CONFIG_DTLK) += dtlk.o
 obj-$(CONFIG_R3964) += n_r3964.o
 obj-$(CONFIG_APPLICOM) += applicom.o
 obj-$(CONFIG_SONYPI) += sonypi.o
 obj-$(CONFIG_RTC) += rtc.o
+obj-$(CONFIG_HPET) += hpet.o
 obj-$(CONFIG_GEN_RTC) += genrtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 ifeq ($(CONFIG_GENERIC_NVRAM),y)
--- diff/drivers/char/agp/amd-k7-agp.c	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/amd-k7-agp.c	2004-05-27 18:34:16.000000000 +0100
@@ -20,6 +20,8 @@
 #define AMD_TLBFLUSH	0x0c	/* In mmio region (32-bit register) */
 #define AMD_CACHEENTRY	0x10	/* In mmio region (32-bit register) */
 
+static struct pci_device_id agp_amdk7_pci_table[];
+
 struct amd_page_map {
 	unsigned long *real;
 	unsigned long *remapped;
@@ -41,7 +43,7 @@
 
 	SetPageReserved(virt_to_page(page_map->real));
 	global_cache_flush();
-	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
+	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
 					    PAGE_SIZE);
 	if (page_map->remapped == NULL) {
 		ClearPageReserved(virt_to_page(page_map->real));
@@ -90,7 +92,7 @@
 	int retval = 0;
 	int i;
 
-	tables = kmalloc((nr_tables + 1) * sizeof(struct amd_page_map *), 
+	tables = kmalloc((nr_tables + 1) * sizeof(struct amd_page_map *),
 			 GFP_KERNEL);
 	if (tables == NULL)
 		return -ENOMEM;
@@ -124,7 +126,7 @@
 #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
 #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
 	GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
-#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) 
+#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
 #define GET_GATT(addr) (amd_irongate_private.gatt_pages[\
 	GET_PAGE_DIR_IDX(addr)]->remapped)
 
@@ -174,7 +176,7 @@
 static int amd_free_gatt_table(void)
 {
 	struct amd_page_map page_dir;
-   
+
 	page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
 	page_dir.remapped = (unsigned long *)agp_bridge->gatt_table;
 
@@ -224,9 +226,9 @@
 
 	/* Write the Sync register */
 	pci_write_config_byte(agp_bridge->dev, AMD_MODECNTL, 0x80);
-   
-   	/* Set indexing mode */
-   	pci_write_config_byte(agp_bridge->dev, AMD_MODECNTL2, 0x00);
+
+	/* Set indexing mode */
+	pci_write_config_byte(agp_bridge->dev, AMD_MODECNTL2, 0x00);
 
 	/* Write the enable register */
 	enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
@@ -394,7 +396,6 @@
 static int __devinit agp_amdk7_probe(struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
 {
-	struct agp_device_ids *devs = amd_agp_device_ids;
 	struct agp_bridge_data *bridge;
 	u8 cap_ptr;
 	int j;
@@ -403,19 +404,10 @@
 	if (!cap_ptr)
 		return -ENODEV;
 
-	for (j = 0; devs[j].chipset_name; j++) {
-		if (pdev->device == devs[j].device_id) {
-			printk (KERN_INFO PFX "Detected AMD %s chipset\n",
-					devs[j].chipset_name);
-			goto found;
-		}
-	}
-
-	printk(KERN_ERR PFX "Unsupported AMD chipset (device id: %04x)\n",
-		    pdev->device);
-	return -ENODEV;
+	j = ent - agp_amdk7_pci_table;
+	printk(KERN_INFO PFX "Detected AMD %s chipset\n",
+	       amd_agp_device_ids[j].chipset_name);
 
-found:
 	bridge = agp_alloc_bridge();
 	if (!bridge)
 		return -ENOMEM;
@@ -442,12 +434,29 @@
 	agp_put_bridge(bridge);
 }
 
+/* must be the same order as name table above */
 static struct pci_device_id agp_amdk7_pci_table[] = {
 	{
 	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
 	.class_mask	= ~0,
 	.vendor		= PCI_VENDOR_ID_AMD,
-	.device		= PCI_ANY_ID,
+	.device		= PCI_DEVICE_ID_AMD_FE_GATE_7006,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_AMD,
+	.device		= PCI_DEVICE_ID_AMD_FE_GATE_700E,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_AMD,
+	.device		= PCI_DEVICE_ID_AMD_FE_GATE_700C,
 	.subvendor	= PCI_ANY_ID,
 	.subdevice	= PCI_ANY_ID,
 	},
--- diff/drivers/char/agp/amd64-agp.c	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/amd64-agp.c	2004-05-27 18:34:16.000000000 +0100
@@ -1,7 +1,7 @@
-/* 
+/*
  * Copyright 2001-2003 SuSE Labs.
  * Distributed under the GNU public license, v2.
- * 
+ *
  * This is a GART driver for the AMD Opteron/Athlon64 on-CPU northbridge.
  * It also includes support for the AMD 8151 AGP bridge,
  * although it doesn't actually do much, as all the real
@@ -194,7 +194,7 @@
 
 	/* keep CPU's coherent. */
 	flush_amd64_tlb (hammer);
-	
+
 	return aper_base;
 }
 
@@ -261,53 +261,53 @@
 
 /* Some basic sanity checks for the aperture. */
 static int __devinit aperture_valid(u64 aper, u32 size)
-{ 
+{
 	u32 pfn, c;
-	if (aper == 0) { 
+	if (aper == 0) {
 		printk(KERN_ERR PFX "No aperture\n");
-		return 0; 
+		return 0;
 	}
 	if (size < 32*1024*1024) {
 		printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20);
 		return 0;
 	}
-	if (aper + size > 0xffffffff) { 
-		printk(KERN_ERR PFX "Aperture out of bounds\n"); 
+	if (aper + size > 0xffffffff) {
+		printk(KERN_ERR PFX "Aperture out of bounds\n");
 		return 0;
-	} 
+	}
 	pfn = aper >> PAGE_SHIFT;
-	for (c = 0; c < size/PAGE_SIZE; c++) { 
+	for (c = 0; c < size/PAGE_SIZE; c++) {
 		if (!pfn_valid(pfn + c))
 			break;
-		if (!PageReserved(pfn_to_page(pfn + c))) { 
+		if (!PageReserved(pfn_to_page(pfn + c))) {
 			printk(KERN_ERR PFX "Aperture pointing to RAM\n");
 			return 0;
 		}
 	}
 
 	/* Request the Aperture. This catches cases when someone else
-	   already put a mapping in there - happens with some very broken BIOS 
+	   already put a mapping in there - happens with some very broken BIOS
 
-	   Maybe better to use pci_assign_resource/pci_enable_device instead trusting
-	   the bridges? */
+	   Maybe better to use pci_assign_resource/pci_enable_device instead
+	   trusting the bridges? */
 	if (!aperture_resource &&
 	    !(aperture_resource = request_mem_region(aper, size, "aperture"))) {
-		printk(KERN_ERR PFX "Aperture conflicts with PCI mapping.\n"); 
+		printk(KERN_ERR PFX "Aperture conflicts with PCI mapping.\n");
 		return 0;
 	}
 	return 1;
-} 
+}
 
-/* 
+/*
  * W*s centric BIOS sometimes only set up the aperture in the AGP
- * bridge, not the northbridge. On AMD64 this is handled early 
+ * bridge, not the northbridge. On AMD64 this is handled early
  * in aperture.c, but when GART_IOMMU is not enabled or we run
- * on a 32bit kernel this needs to be redone. 
+ * on a 32bit kernel this needs to be redone.
  * Unfortunately it is impossible to fix the aperture here because it's too late
  * to allocate that much memory. But at least error out cleanly instead of
  * crashing.
- */ 
-static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, 
+ */
+static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
 								 u16 cap)
 {
 	u32 aper_low, aper_hi;
@@ -316,38 +316,38 @@
 	u32 nb_order, nb_base;
 	u16 apsize;
 
-	pci_read_config_dword(nb, 0x90, &nb_order); 
+	pci_read_config_dword(nb, 0x90, &nb_order);
 	nb_order = (nb_order >> 1) & 7;
-	pci_read_config_dword(nb, 0x94, &nb_base); 
-	nb_aper = nb_base << 25;	
-	if (aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) { 
+	pci_read_config_dword(nb, 0x94, &nb_base);
+	nb_aper = nb_base << 25;
+	if (aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) {
 		return 0;
 	}
 
 	/* Northbridge seems to contain crap. Try the AGP bridge. */
 
-	pci_read_config_word(agp, cap+0x14, &apsize); 
-	if (apsize == 0xffff) 
-		return -1; 
+	pci_read_config_word(agp, cap+0x14, &apsize);
+	if (apsize == 0xffff)
+		return -1;
 
 	apsize &= 0xfff;
 	/* Some BIOS use weird encodings not in the AGPv3 table. */
-	if (apsize & 0xff) 
-		apsize |= 0xf00; 
-	order = 7 - hweight16(apsize); 
+	if (apsize & 0xff)
+		apsize |= 0xf00;
+	order = 7 - hweight16(apsize);
 
 	pci_read_config_dword(agp, 0x10, &aper_low);
 	pci_read_config_dword(agp, 0x14, &aper_hi);
-	aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); 
+	aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
 	printk(KERN_INFO PFX "Aperture from AGP @ %Lx size %u MB\n", aper, 32 << order);
 	if (order < 0 || !aperture_valid(aper, (32*1024*1024)<<order))
-		return -1; 
-	
-	pci_write_config_dword(nb, 0x90, order << 1); 
-	pci_write_config_dword(nb, 0x94, aper >> 25); 
+		return -1;
+
+	pci_write_config_dword(nb, 0x90, order << 1);
+	pci_write_config_dword(nb, 0x94, aper >> 25);
 
 	return 0;
-} 
+}
 
 static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
 {
@@ -355,19 +355,19 @@
 	int i = 0;
 
 	/* cache pci_devs of northbridges. */
-	while ((loop_dev = pci_find_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev)) 
+	while ((loop_dev = pci_find_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev))
 			!= NULL) {
-		if (i == MAX_HAMMER_GARTS) { 
+		if (i == MAX_HAMMER_GARTS) {
 			printk(KERN_ERR PFX "Too many northbridges for AGP\n");
 			return -1;
 		}
-		if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) { 
+		if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) {
 			printk(KERN_ERR PFX "No usable aperture found.\n");
-#ifdef __x86_64__ 
+#ifdef __x86_64__
 			/* should port this to i386 */
 			printk(KERN_ERR PFX "Consider rebooting with iommu=memaper=2 to get a good aperture.\n");
-#endif 
-			return -1;  
+#endif
+			return -1;
 		}
 		hammers[i++] = loop_dev;
 	}
@@ -377,8 +377,7 @@
 
 /* Handle AMD 8151 quirks */
 static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data *bridge)
-
-{		
+{
 	char *revstring;
 	u8 rev_id;
 
@@ -417,12 +416,12 @@
 
 /* Handle shadow device of the Nvidia NForce3 */
 /* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */
-static int __devinit nforce3_agp_init(struct pci_dev *pdev) 
-{ 
+static int __devinit nforce3_agp_init(struct pci_dev *pdev)
+{
 	u32 tmp, apbase, apbar, aplimit;
-	struct pci_dev *dev1; 
+	struct pci_dev *dev1;
 	int i;
-	unsigned size = amd64_fetch_size(); 
+	unsigned size = amd64_fetch_size();
 
 	printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n");
 
@@ -432,17 +431,17 @@
 			"nForce3 chipset, but could not find "
 			"the secondary device.\n");
 		return -ENODEV;
-	}	
+	}
 
-	for (i = 0; i < ARRAY_SIZE(nforce3_sizes); i++) 
+	for (i = 0; i < ARRAY_SIZE(nforce3_sizes); i++)
 		if (nforce3_sizes[i].size == size)
-			break; 
+			break;
 
 	if (i == ARRAY_SIZE(nforce3_sizes)) {
-		printk(KERN_INFO PFX "No NForce3 size found for %d\n", size); 
-		return -ENODEV; 
+		printk(KERN_INFO PFX "No NForce3 size found for %d\n", size);
+		return -ENODEV;
 	}
-	
+
 	pci_read_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, &tmp);
 	tmp &= ~(0xf);
 	tmp |= nforce3_sizes[i].size_value;
@@ -491,8 +490,7 @@
 	    pdev->device == PCI_DEVICE_ID_AMD_8151_0) {
 		amd8151_init(pdev, bridge);
 	} else {
-		printk(KERN_INFO PFX "Detected AGP bridge %x\n",
-			pdev->devfn);
+		printk(KERN_INFO PFX "Detected AGP bridge %x\n", pdev->devfn);
 	}
 
 	bridge->driver = &amd_8151_driver;
@@ -507,10 +505,10 @@
 		return -ENODEV;
 	}
 
-	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { 
+	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
 		int ret = nforce3_agp_init(pdev);
-		if (ret) { 
-			agp_put_bridge(bridge); 
+		if (ret) {
+			agp_put_bridge(bridge);
 			return ret;
 		}
 	}
@@ -523,8 +521,8 @@
 {
 	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
-	release_mem_region(virt_to_phys(bridge->gatt_table_real), 
-			   amd64_aperture_sizes[bridge->aperture_size_idx].size); 
+	release_mem_region(virt_to_phys(bridge->gatt_table_real),
+			   amd64_aperture_sizes[bridge->aperture_size_idx].size);
 	agp_remove_bridge(bridge);
 	agp_put_bridge(bridge);
 }
@@ -581,6 +579,15 @@
 	.subvendor	= PCI_ANY_ID,
 	.subdevice	= PCI_ANY_ID,
 	},
+	/* SIS 755 */
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_SI,
+	.device		= PCI_DEVICE_ID_SI_755,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
 	{ }
 };
 
@@ -600,15 +607,15 @@
 	int err = 0;
 	if (agp_off)
 		return -EINVAL;
-	if (pci_module_init(&agp_amd64_pci_driver) > 0) { 
+	if (pci_module_init(&agp_amd64_pci_driver) > 0) {
 		struct pci_dev *dev;
-		if (!agp_try_unsupported && !agp_try_unsupported_boot) { 
+		if (!agp_try_unsupported && !agp_try_unsupported_boot) {
 			printk(KERN_INFO PFX "No supported AGP bridge found.\n");
-#ifdef MODULE			
+#ifdef MODULE
 			printk(KERN_INFO PFX "You can try agp_try_unsupported=1\n");
 #else
 			printk(KERN_INFO PFX "You can boot with agp=try_unsupported\n");
-#endif			
+#endif
 			return -ENODEV;
 		}
 
@@ -622,12 +629,12 @@
 		while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev))) {
 			if (!pci_find_capability(dev, PCI_CAP_ID_AGP))
 				continue;
-			/* Only one bridge supported right now */	
+			/* Only one bridge supported right now */
 			if (agp_amd64_probe(dev, NULL) == 0) {
 				err = 0;
 				break;
-			}	
-		}		
+			}
+		}
 	}
 	return err;
 }
--- diff/drivers/char/agp/ati-agp.c	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/ati-agp.c	2004-05-27 18:34:16.000000000 +0100
@@ -131,6 +131,7 @@
 				i--;
 			}
 			kfree (tables);
+			tables = NULL;
 			retval = -ENOMEM;
 			break;
 		}
--- diff/drivers/char/agp/intel-agp.c	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/intel-agp.c	2004-05-27 18:34:16.000000000 +0100
@@ -1233,7 +1233,7 @@
 				name);
 		return 0;
 	}
-	
+
 	intel_i810_private.i810_dev = i810_dev;
 	return 1;
 }
@@ -1384,6 +1384,7 @@
 	default:
 		printk(KERN_ERR PFX "Unsupported Intel chipset (device id: %04x)\n",
 			    pdev->device);
+		agp_put_bridge(bridge);
 		return -ENODEV;
 	};
 
@@ -1406,7 +1407,8 @@
 	if (!r->start && r->end) {
 		if(pci_assign_resource(pdev, 0)) {
 			printk(KERN_ERR PFX "could not assign resource 0\n");
-			return (-ENODEV);
+			agp_put_bridge(bridge);
+			return -ENODEV;
 		}
 	}
 
@@ -1417,7 +1419,8 @@
 	*/
 	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR PFX "Unable to Enable PCI device\n");
-		return (-ENODEV);
+		agp_put_bridge(bridge);
+		return -ENODEV;
 	}
 
 	/* Fill in the mode register */
@@ -1462,14 +1465,37 @@
 }
 
 static struct pci_device_id agp_intel_pci_table[] = {
-	{
-	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
-	.class_mask	= ~0,
-	.vendor		= PCI_VENDOR_ID_INTEL,
-	.device		= PCI_ANY_ID,
-	.subvendor	= PCI_ANY_ID,
-	.subdevice	= PCI_ANY_ID,
-	},
+#define ID(x)						\
+	{ 						\
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),	\
+	.class_mask	= ~0,				\
+	.vendor		= PCI_VENDOR_ID_INTEL,		\
+	.device		= x,				\
+	.subvendor	= PCI_ANY_ID,			\
+	.subdevice	= PCI_ANY_ID,			\
+	}
+	ID(PCI_DEVICE_ID_INTEL_82443LX_0),
+	ID(PCI_DEVICE_ID_INTEL_82443BX_0),
+	ID(PCI_DEVICE_ID_INTEL_82443GX_0),
+	ID(PCI_DEVICE_ID_INTEL_82810_MC1),
+	ID(PCI_DEVICE_ID_INTEL_82810_MC3),
+	ID(PCI_DEVICE_ID_INTEL_82810E_MC),
+	ID(PCI_DEVICE_ID_INTEL_82815_MC),
+	ID(PCI_DEVICE_ID_INTEL_82820_HB),
+	ID(PCI_DEVICE_ID_INTEL_82820_UP_HB),
+	ID(PCI_DEVICE_ID_INTEL_82830_HB),
+	ID(PCI_DEVICE_ID_INTEL_82840_HB),
+	ID(PCI_DEVICE_ID_INTEL_82845_HB),
+	ID(PCI_DEVICE_ID_INTEL_82845G_HB),
+	ID(PCI_DEVICE_ID_INTEL_82850_HB),
+	ID(PCI_DEVICE_ID_INTEL_82855PM_HB),
+	ID(PCI_DEVICE_ID_INTEL_82855GM_HB),
+	ID(PCI_DEVICE_ID_INTEL_82860_HB),
+	ID(PCI_DEVICE_ID_INTEL_82865_HB),
+	ID(PCI_DEVICE_ID_INTEL_82875_HB),
+	ID(PCI_DEVICE_ID_INTEL_7505_0),
+	ID(PCI_DEVICE_ID_INTEL_7501_0),
+	ID(PCI_DEVICE_ID_INTEL_7205_0),
 	{ }
 };
 
--- diff/drivers/char/agp/intel-mch-agp.c	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/intel-mch-agp.c	2004-05-27 18:34:16.000000000 +0100
@@ -491,10 +491,9 @@
 	char *name = "(unknown)";
 	u8 cap_ptr = 0;
 
-	if (!boot_cpu_has(X86_FEATURE_LM))
-		return -ENODEV;
-
 	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (!cap_ptr) 
+		return -ENODEV;
 
 	bridge = agp_alloc_bridge();
 	if (!bridge)
@@ -590,7 +589,15 @@
 	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
 	.class_mask	= ~0,
 	.vendor		= PCI_VENDOR_ID_INTEL,
-	.device		= PCI_ANY_ID,
+	.device		= PCI_DEVICE_ID_INTEL_82865_HB,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_INTEL,
+	.device		= PCI_DEVICE_ID_INTEL_82875_HB,
 	.subvendor	= PCI_ANY_ID,
 	.subdevice	= PCI_ANY_ID,
 	},
--- diff/drivers/char/agp/nvidia-agp.c	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/nvidia-agp.c	2004-05-27 18:34:16.000000000 +0100
@@ -380,7 +380,15 @@
 	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
 	.class_mask	= ~0,
 	.vendor		= PCI_VENDOR_ID_NVIDIA,
-	.device		= PCI_ANY_ID,
+	.device		= PCI_DEVICE_ID_NVIDIA_NFORCE,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_NVIDIA,
+	.device		= PCI_DEVICE_ID_NVIDIA_NFORCE2,
 	.subvendor	= PCI_ANY_ID,
 	.subdevice	= PCI_ANY_ID,
 	},
--- diff/drivers/char/agp/sis-agp.c	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/sis-agp.c	2004-05-27 18:34:16.000000000 +0100
@@ -13,6 +13,8 @@
 #define SIS_TLBCNTRL	0x97
 #define SIS_TLBFLUSH	0x98
 
+static int __devinitdata agp_sis_force_delay = 0;
+static int __devinitdata agp_sis_agp_spec = -1;
 
 static int sis_fetch_size(void)
 {
@@ -67,7 +69,7 @@
 			      (previous_size->size_value & ~(0x03)));
 }
 
-static void sis_648_enable(u32 mode)
+static void sis_delayed_enable(u32 mode)
 {
 	struct pci_dev *device = NULL;
 	u32 command;
@@ -94,13 +96,12 @@
 		pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command);
 
 		/*
-		 * Weird: on 648(fx) and 746(fx) chipsets any rate change in the target
+		 * Weird: on some sis chipsets any rate change in the target
 		 * command register triggers a 5ms screwup during which the master
 		 * cannot be configured		 
 		 */
-		if (device->device == PCI_DEVICE_ID_SI_648 ||
-		    device->device == PCI_DEVICE_ID_SI_746) {
-			printk(KERN_INFO PFX "SiS chipset with AGP problems detected. Giving bridge time to recover.\n");
+		if (device->device == agp_bridge->dev->device) {
+			printk(KERN_INFO PFX "SiS delay workaround: giving bridge time to recover.\n");
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout (1+(HZ*10)/1000);
 		}
@@ -223,28 +224,35 @@
 };
 
 
+// chipsets that require the 'delay hack'
+static int sis_broken_chipsets[] __devinitdata = {
+	PCI_DEVICE_ID_SI_648,
+	PCI_DEVICE_ID_SI_746,
+	0 // terminator
+};
+
 static void __devinit sis_get_driver(struct agp_bridge_data *bridge)
 {
-	if (bridge->dev->device == PCI_DEVICE_ID_SI_648) { 
-		sis_driver.agp_enable=sis_648_enable;
-		if (agp_bridge->major_version == 3) {
-			sis_driver.aperture_sizes = agp3_generic_sizes;
-			sis_driver.size_type = U16_APER_SIZE;
-			sis_driver.num_aperture_sizes = AGP_GENERIC_SIZES_ENTRIES;
-			sis_driver.configure = agp3_generic_configure;
-			sis_driver.fetch_size = agp3_generic_fetch_size;
-			sis_driver.cleanup = agp3_generic_cleanup;
-			sis_driver.tlb_flush = agp3_generic_tlbflush;
-		}
-	}
+	int i;
 
-	if (bridge->dev->device == PCI_DEVICE_ID_SI_746) {
-		/*
-		 * We don't know enough about the 746 to enable it properly.
-		 * Though we do know that it needs the 'delay' hack to settle
-		 * after changing modes.
-		 */
-		sis_driver.agp_enable=sis_648_enable;
+	for(i=0; sis_broken_chipsets[i]!=0; ++i)
+		if(bridge->dev->device==sis_broken_chipsets[i])
+			break;
+
+	if(sis_broken_chipsets[i] || agp_sis_force_delay)
+		sis_driver.agp_enable=sis_delayed_enable;
+
+	// sis chipsets that indicate less than agp3.5
+	// are not actually fully agp3 compliant
+	if ((agp_bridge->major_version == 3 && agp_bridge->minor_version >= 5
+	     && agp_sis_agp_spec!=0) || agp_sis_agp_spec==1) {
+		sis_driver.aperture_sizes = agp3_generic_sizes;
+		sis_driver.size_type = U16_APER_SIZE;
+		sis_driver.num_aperture_sizes = AGP_GENERIC_SIZES_ENTRIES;
+		sis_driver.configure = agp3_generic_configure;
+		sis_driver.fetch_size = agp3_generic_fetch_size;
+		sis_driver.cleanup = agp3_generic_cleanup;
+		sis_driver.tlb_flush = agp3_generic_tlbflush;
 	}
 }
 
@@ -335,4 +343,8 @@
 module_init(agp_sis_init);
 module_exit(agp_sis_cleanup);
 
+MODULE_PARM(agp_sis_force_delay,"i");
+MODULE_PARM_DESC(agp_sis_force_delay,"forces sis delay hack");
+MODULE_PARM(agp_sis_agp_spec,"i");
+MODULE_PARM_DESC(agp_sis_agp_spec,"0=force sis init, 1=force generic agp3 init, default: autodetect");
 MODULE_LICENSE("GPL and additional rights");
--- diff/drivers/char/agp/via-agp.c	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/via-agp.c	2004-05-27 18:34:16.000000000 +0100
@@ -9,6 +9,8 @@
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+static struct pci_device_id agp_via_pci_table[];
+
 #define VIA_GARTCTRL	0x80
 #define VIA_APSIZE	0x84
 #define VIA_ATTBASE	0x88
@@ -378,20 +380,9 @@
 	if (!cap_ptr)
 		return -ENODEV;
 
-	/* probe for known chipsets */
-	for (j = 0; devs[j].chipset_name; j++) {
-		if (pdev->device == devs[j].device_id) {
-			printk (KERN_INFO PFX "Detected VIA %s chipset\n",
-					devs[j].chipset_name);
-			goto found;
-		}
-	}
-
-	printk(KERN_ERR PFX "Unsupported VIA chipset (device id: %04x)\n",
-		    pdev->device);
-	return -ENODEV;
+	j = ent - agp_via_pci_table;
+	printk (KERN_INFO PFX "Detected VIA %s chipset\n", devs[j].chipset_name);
 
-found:
 	bridge = agp_alloc_bridge();
 	if (!bridge)
 		return -ENOMEM;
@@ -432,15 +423,40 @@
 	agp_put_bridge(bridge);
 }
 
+/* must be the same order as name table above */
 static struct pci_device_id agp_via_pci_table[] = {
-	{
-	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
-	.class_mask	= ~0,
-	.vendor		= PCI_VENDOR_ID_VIA,
-	.device		= PCI_ANY_ID,
-	.subvendor	= PCI_ANY_ID,
-	.subdevice	= PCI_ANY_ID,
-	},
+#define ID(x) \
+	{						\
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),	\
+	.class_mask	= ~0,				\
+	.vendor		= PCI_VENDOR_ID_VIA,		\
+	.device		= x,				\
+	.subvendor	= PCI_ANY_ID,			\
+	.subdevice	= PCI_ANY_ID,			\
+	}
+	ID(PCI_DEVICE_ID_VIA_82C598_0),
+	ID(PCI_DEVICE_ID_VIA_8501_0),
+	ID(PCI_DEVICE_ID_VIA_8601_0),
+	ID(PCI_DEVICE_ID_VIA_82C691_0),
+	ID(PCI_DEVICE_ID_VIA_8371_0),
+	ID(PCI_DEVICE_ID_VIA_8633_0),
+	ID(PCI_DEVICE_ID_VIA_XN266),
+	ID(PCI_DEVICE_ID_VIA_8361),
+	ID(PCI_DEVICE_ID_VIA_8363_0),
+	ID(PCI_DEVICE_ID_VIA_8753_0),
+	ID(PCI_DEVICE_ID_VIA_8367_0),
+	ID(PCI_DEVICE_ID_VIA_8653_0),
+	ID(PCI_DEVICE_ID_VIA_XM266),
+	ID(PCI_DEVICE_ID_VIA_862X_0),
+	ID(PCI_DEVICE_ID_VIA_8377_0),
+	ID(PCI_DEVICE_ID_VIA_8605_0),
+	ID(PCI_DEVICE_ID_VIA_8703_51_0),
+	ID(PCI_DEVICE_ID_VIA_8754C_0),
+	ID(PCI_DEVICE_ID_VIA_8763_0),
+	ID(PCI_DEVICE_ID_VIA_8378_0),
+	ID(PCI_DEVICE_ID_VIA_PT880),
+	ID(PCI_DEVICE_ID_VIA_8783_0),
+	ID(PCI_DEVICE_ID_VIA_PX8X0_0),	
 	{ }
 };
 
--- diff/drivers/char/keyboard.c	2004-05-19 22:11:34.000000000 +0100
+++ source/drivers/char/keyboard.c	2004-05-27 18:34:16.000000000 +0100
@@ -52,13 +52,12 @@
 
 /*
  * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On PC9800 and HIL keyboards 
+ * This seems a good reason to start with NumLock off. On HIL keyboards
  * of PARISC machines however there is no NumLock key and everyone expects the keypad 
  * to be used for numbers.
  */
 
-#if defined(CONFIG_X86_PC9800) || \
-    defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
+#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
 #define KBD_DEFLEDS (1 << VC_NUMLOCK)
 #else
 #define KBD_DEFLEDS 0
@@ -1066,6 +1065,9 @@
 	}
 	if (sysrq_down && down && !rep) {
 		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
+#ifdef CONFIG_KGDB_SYSRQ
+                sysrq_down = 0;        /* in case we miss the "up" event */
+#endif
 		return;
 	}
 #endif
--- diff/drivers/char/mem.c	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/char/mem.c	2004-05-27 18:34:16.000000000 +0100
@@ -26,7 +26,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 
 #ifdef CONFIG_IA64
 # include <linux/efi.h>
@@ -39,6 +38,7 @@
 extern void tapechar_init(void);
 #endif
 
+#ifdef pgprot_noncached
 /*
  * Architectures vary in how they handle caching for addresses
  * outside of main memory.
@@ -77,7 +77,8 @@
 	return 0;
 #elif defined(CONFIG_IA64)
 	/*
-	 * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
+	 * On ia64, we ignore O_SYNC because we cannot tolerate memory
+	 * attribute aliases.
 	 */
 	return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
 #elif defined(CONFIG_PPC64)
@@ -90,14 +91,15 @@
 	return !page_is_ram(addr);
 #else
 	/*
-	 * Accessing memory above the top the kernel knows about or through a file pointer
-	 * that was marked O_SYNC will be done non-cached.
+	 * Accessing memory above the top the kernel knows about or through a
+	 * file pointer that was marked O_SYNC will be done non-cached.
 	 */
 	if (file->f_flags & O_SYNC)
 		return 1;
 	return addr >= __pa(high_memory);
 #endif
 }
+#endif
 
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
 static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
@@ -194,28 +196,24 @@
 	return do_write_mem(__va(p), p, buf, count, ppos);
 }
 
-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+static int mmap_mem(struct file *file, struct vm_area_struct *vma)
 {
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	int uncached;
 
-	uncached = uncached_access(file, offset);
 #ifdef pgprot_noncached
-	if (uncached)
+	if (uncached_access(file, offset))
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #endif
 
-	/* Don't try to swap out physical pages.. */
-	vma->vm_flags |= VM_RESERVED;
-
 	/*
-	 * Don't dump addresses that are not real memory to a core file.
+	 * Don't try to swap out physical pages..
+	 * And treat /dev/mem mappings as "IO" regions: they may not
+	 * describe valid pageframes.
 	 */
-	if (uncached)
-		vma->vm_flags |= VM_IO;
+	vma->vm_flags |= VM_RESERVED|VM_IO;
 
-	if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
-			     vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, offset,
+			vma->vm_end-vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
 }
--- diff/drivers/char/rtc.c	2004-05-19 22:11:34.000000000 +0100
+++ source/drivers/char/rtc.c	2004-05-27 18:34:16.000000000 +0100
@@ -97,6 +97,11 @@
 static int rtc_irq = PCI_IRQ_NONE;
 #endif
 
+#ifdef	CONFIG_HPET_RTC_IRQ
+#undef	RTC_IRQ
+#define	RTC_IRQ	0
+#endif
+
 #if RTC_IRQ
 static int rtc_has_irq = 1;
 #endif
--- diff/drivers/char/sysrq.c	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/char/sysrq.c	2004-05-27 18:34:16.000000000 +0100
@@ -35,6 +35,25 @@
 #include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
+#ifdef CONFIG_KGDB_SYSRQ
+
+#define  GDB_OP &kgdb_op
+static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+{
+	printk("kgdb sysrq\n");
+	breakpoint();
+}
+
+static struct sysrq_key_op kgdb_op = {
+	.handler	= kgdb_sysrq,
+	.help_msg	= "kGdb|Fgdb",
+	.action_msg	= "Debug breakpoint\n",
+};
+
+#else
+#define  GDB_OP NULL
+#endif
+
 
 extern void reset_vc(unsigned int);
 
@@ -238,8 +257,8 @@
 /* c */ NULL,
 /* d */	NULL,
 /* e */	&sysrq_term_op,
-/* f */	NULL,
-/* g */	NULL,
+/* f */	GDB_OP,
+/* g */	GDB_OP,
 /* h */	NULL,
 /* i */	&sysrq_kill_op,
 /* j */	NULL,
--- diff/drivers/char/tty_io.c	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/char/tty_io.c	2004-05-27 18:34:16.000000000 +0100
@@ -91,6 +91,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
+#include <linux/idr.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -128,6 +129,8 @@
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver *ptm_driver;	/* Unix98 pty masters; for /dev/ptmx */
 extern int pty_limit;		/* Config limit on Unix98 ptys */
+static DEFINE_IDR(allocated_ptys);
+static DECLARE_MUTEX(allocated_ptys_lock);
 #endif
 
 extern void disable_early_printk(void);
@@ -1295,6 +1298,14 @@
 		o_tty->ldisc = ldiscs[N_TTY];
 	}
 
+#ifdef CONFIG_UNIX98_PTYS
+	if (filp->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,2)) {
+		down(&allocated_ptys_lock);
+		idr_remove(&allocated_ptys, idx);
+		up(&allocated_ptys_lock);
+	}
+#endif
+
 	/* 
 	 * The release_mem function takes care of the details of clearing
 	 * the slots and preserving the termios structure.
@@ -1319,7 +1330,7 @@
 	struct tty_struct *tty;
 	int noctty, retval;
 	struct tty_driver *driver;
-	int index;
+	int index = -1;
 	dev_t device = inode->i_rdev;
 	unsigned short saved_flags = filp->f_flags;
 retry_open:
@@ -1361,23 +1372,41 @@
 
 #ifdef CONFIG_UNIX98_PTYS
 	if (device == MKDEV(TTYAUX_MAJOR,2)) {
+		int idr_ret;
+
 		/* find a device that is not in use. */
-		static int next_ptmx_dev = 0;
-		retval = -1;
+		down(&allocated_ptys_lock);
+		if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
+			up(&allocated_ptys_lock);
+			return -ENOMEM;
+		}
+		idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
+		if (idr_ret < 0) {
+			up(&allocated_ptys_lock);
+			if (idr_ret == -EAGAIN)
+				return -ENOMEM;
+			return -EIO;
+		}
+		if (index >= pty_limit) {
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+			return -EIO;
+		}
 		driver = ptm_driver;
-		while (driver->refcount < pty_limit) {
-			index = next_ptmx_dev;
-			next_ptmx_dev = (next_ptmx_dev+1) % driver->num;
-			if (!init_dev(driver, index, &tty))
-				goto ptmx_found; /* ok! */
+		retval = init_dev(driver, index, &tty);
+		if (retval) {
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+			return retval;
 		}
-		return -EIO; /* no free ptys */
-	ptmx_found:
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 		if (devpts_pty_new(tty->link)) {
 			/* BADNESS - need to destroy both ptm and pts! */
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
 			return -ENOMEM;
 		}
+		up(&allocated_ptys_lock);
 		noctty = 1;
 	} else
 #endif
@@ -1415,6 +1444,14 @@
 		       tty->name);
 #endif
 
+#ifdef CONFIG_UNIX98_PTYS
+		if (index != -1) {
+			down(&allocated_ptys_lock);
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+		}
+#endif
+
 		release_dev(filp);
 		if (retval != -ERESTARTSYS)
 			return retval;
--- diff/drivers/char/watchdog/wdt.c	2004-05-19 22:11:39.000000000 +0100
+++ source/drivers/char/watchdog/wdt.c	2004-05-27 18:34:16.000000000 +0100
@@ -633,8 +633,8 @@
 outmisc:
 #ifdef CONFIG_WDT_501
 	misc_deregister(&temp_miscdev);
-#endif /* CONFIG_WDT_501 */
 outrbt:
+#endif /* CONFIG_WDT_501 */
 	unregister_reboot_notifier(&wdt_notifier);
 outirq:
 	free_irq(irq, NULL);
--- diff/drivers/firmware/smbios.c	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/firmware/smbios.c	2004-05-27 18:34:16.000000000 +0100
@@ -126,7 +126,7 @@
 	if(keep_going != 0)
 		printk(KERN_INFO "Warning: SMBIOS table does not end with a"
 				" structure type 127. This may indicate a"
-				" truncated table.");
+				" truncated table.\n");
 
 	if(sdev->smbios_table_real_length != max_length)
 		printk(KERN_INFO "Warning: BIOS specified SMBIOS table length"
--- diff/drivers/i2c/busses/Kconfig	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/i2c/busses/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -118,8 +118,14 @@
 	  will be called i2c-i810.
 
 config I2C_IBM_IIC
-	tristate "IBM IIC I2C"
+	tristate "IBM PPC 4xx on-chip I2C interface"
 	depends on IBM_OCP && I2C
+	help
+	  Say Y here if you want to use IIC peripheral found on 
+	  embedded IBM PPC 4xx based systems. 
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-ibm_iic.
 
 config I2C_IOP3XX
 	tristate "Intel XScale IOP3xx on-chip I2C interface"
--- diff/drivers/i2c/busses/i2c-ibm_iic.c	2004-05-19 22:11:39.000000000 +0100
+++ source/drivers/i2c/busses/i2c-ibm_iic.c	2004-05-27 18:34:16.000000000 +0100
@@ -3,7 +3,7 @@
  *
  * Support for the IIC peripheral on IBM PPC 4xx
  *
- * Copyright (c) 2003 Zultys Technologies.
+ * Copyright (c) 2003, 2004 Zultys Technologies.
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *
  * Based on original work by 
@@ -45,7 +45,7 @@
 
 #include "i2c-ibm_iic.h"
 
-#define DRIVER_VERSION "2.0"
+#define DRIVER_VERSION "2.01"
 
 MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
 MODULE_LICENSE("GPL");
@@ -69,14 +69,14 @@
 #endif
 
 #if DBG_LEVEL > 0
-#  define DBG(x...)	printk(KERN_DEBUG "ibm-iic" ##x)
+#  define DBG(f,x...)	printk(KERN_DEBUG "ibm-iic" f, ##x)
 #else
-#  define DBG(x...)	((void)0)
+#  define DBG(f,x...)	((void)0)
 #endif
 #if DBG_LEVEL > 1
-#  define DBG2(x...) 	DBG( ##x )
+#  define DBG2(f,x...) 	DBG(f, ##x)
 #else
-#  define DBG2(x...) 	((void)0)
+#  define DBG2(f,x...) 	((void)0)
 #endif
 #if DBG_LEVEL > 2
 static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
@@ -455,6 +455,16 @@
 	}		
 	for (i = 0; i < num; ++i){
 		if (unlikely(msgs[i].len <= 0)){
+			if (num == 1 && !msgs[0].len){
+				/* Special case for I2C_SMBUS_QUICK emulation.
+				 * Although this logic is FAR FROM PERFECT, this 
+				 * is what previous driver version did.
+				 * IBM IIC doesn't support 0-length transactions
+				 * (except bit-banging through IICx_DIRECTCNTL).
+				 */
+				DBG("%d: zero-length msg kludge\n", dev->idx); 
+				return 0;
+			}
 			DBG("%d: invalid len %d in msg[%d]\n", dev->idx, 
 				msgs[i].len, i);
 			return -EINVAL;
@@ -549,19 +559,24 @@
 
 	struct ibm_iic_private* dev;
 	struct i2c_adapter* adap;
+	struct ocp_func_iic_data* iic_data = ocp->def->additions;
 	int ret;
-	bd_t* bd = (bd_t*)&__res;
 	
+	if (!iic_data)
+		printk(KERN_WARNING"ibm-iic%d: missing additional data!\n",
+			ocp->def->index);
+
 	if (!(dev = kmalloc(sizeof(*dev), GFP_KERNEL))){
-		printk(KERN_CRIT "ibm-iic: failed to allocate device data\n");
+		printk(KERN_CRIT "ibm-iic%d: failed to allocate device data\n",
+			ocp->def->index);
 		return -ENOMEM;
 	}
 
 	memset(dev, 0, sizeof(*dev));
-	dev->idx = ocp->num;
+	dev->idx = ocp->def->index;
 	ocp_set_drvdata(ocp, dev);
 	
-	if (!(dev->vaddr = ioremap(ocp->paddr, sizeof(struct iic_regs)))){
+	if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){
 		printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
 			dev->idx);
 		ret = -ENXIO;
@@ -570,7 +585,7 @@
 	
 	init_waitqueue_head(&dev->wq);
 
-	dev->irq = iic_force_poll ? -1 : ocp->irq;
+	dev->irq = iic_force_poll ? -1 : ocp->def->irq;
 	if (dev->irq >= 0){
 		/* Disable interrupts until we finish intialization,
 		   assumes level-sensitive IRQ setup...
@@ -589,13 +604,12 @@
 			dev->idx);
 		
 	/* Board specific settings */
-	BUG_ON(dev->idx >= sizeof(bd->bi_iic_fast) / sizeof(bd->bi_iic_fast[0]));
-	dev->fast_mode = iic_force_fast ? 1 : bd->bi_iic_fast[dev->idx];
+	dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0);
 	
 	/* clckdiv is the same for *all* IIC interfaces, 
 	 * but I'd rather make a copy than introduce another global. --ebs
 	 */
-	dev->clckdiv = iic_clckdiv(bd->bi_opb_busfreq);
+	dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq);
 	DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
 	
 	/* Initialize IIC interface */
@@ -664,7 +678,7 @@
 
 static struct ocp_device_id ibm_iic_ids[] __devinitdata = 
 {
-	{ .vendor = OCP_VENDOR_IBM, .device = OCP_FUNC_IIC },
+	{ .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC },
 	{ .vendor = OCP_VENDOR_INVALID }
 };
 
@@ -672,7 +686,7 @@
 
 static struct ocp_driver ibm_iic_driver =
 {
-	.name 		= "ocp_iic",
+	.name 		= "iic",
 	.id_table	= ibm_iic_ids,
 	.probe		= iic_probe,
 	.remove		= __devexit_p(iic_remove),
@@ -685,7 +699,7 @@
 static int __init iic_init(void)
 {
 	printk(KERN_INFO "IBM IIC driver v" DRIVER_VERSION "\n");
-	return ocp_module_init(&ibm_iic_driver);
+	return ocp_register_driver(&ibm_iic_driver);
 }
 
 static void __exit iic_exit(void)
--- diff/drivers/i2c/chips/eeprom.c	2004-05-19 22:11:40.000000000 +0100
+++ source/drivers/i2c/chips/eeprom.c	2004-05-27 18:34:16.000000000 +0100
@@ -203,11 +203,12 @@
 	new_client->driver = &eeprom_driver;
 	new_client->flags = 0;
 
+	/* prevent 24RF08 corruption */
+	i2c_smbus_write_quick(new_client, 0);
+
 	/* Now, we do the remaining detection. It is not there, unless you force
 	   the checksum to work out. */
 	if (checksum) {
-		/* prevent 24RF08 corruption */
-		i2c_smbus_write_quick(new_client, 0);
 		cs = 0;
 		for (i = 0; i <= 0x3e; i++)
 			cs += i2c_smbus_read_byte_data(new_client, i);
--- diff/drivers/i2c/i2c-core.c	2004-05-19 22:11:39.000000000 +0100
+++ source/drivers/i2c/i2c-core.c	2004-05-27 18:34:16.000000000 +0100
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
+#include <linux/idr.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
 
@@ -35,6 +36,7 @@
 static LIST_HEAD(adapters);
 static LIST_HEAD(drivers);
 static DECLARE_MUTEX(core_lists);
+static DEFINE_IDR(i2c_adapter_idr);
 
 int i2c_device_probe(struct device *dev)
 {
@@ -113,13 +115,25 @@
  */
 int i2c_add_adapter(struct i2c_adapter *adap)
 {
-	static int nr = 0;
+	int id, res = 0;
 	struct list_head   *item;
 	struct i2c_driver  *driver;
 
 	down(&core_lists);
 
-	adap->nr = nr++;
+	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
+		res = -ENOMEM;
+		goto out_unlock;
+	}
+
+	res = idr_get_new(&i2c_adapter_idr, NULL, &id);
+	if (res < 0) {
+		if (res == -EAGAIN)
+			res = -ENOMEM;
+		goto out_unlock;
+	}
+
+	adap->nr =  id & MAX_ID_MASK;
 	init_MUTEX(&adap->bus_lock);
 	init_MUTEX(&adap->clist_lock);
 	list_add_tail(&adap->list,&adapters);
@@ -151,10 +165,12 @@
 			/* We ignore the return code; if it fails, too bad */
 			driver->attach_adapter(adap);
 	}
-	up(&core_lists);
 
 	dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr);
-	return 0;
+
+out_unlock:
+	up(&core_lists);
+	return res;
 }
 
 
@@ -208,6 +224,9 @@
 	wait_for_completion(&adap->dev_released);
 	wait_for_completion(&adap->class_dev_released);
 
+	/* free dynamically allocated bus id */
+	idr_remove(&i2c_adapter_idr, adap->nr);
+
 	dev_dbg(&adap->dev, "adapter unregistered\n");
 
  out_unlock:
--- diff/drivers/ide/Kconfig	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/ide/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -97,25 +97,7 @@
 
 config BLK_DEV_HD_IDE
 	bool "Use old disk-only driver on primary interface"
-	depends on ((X86 && X86_PC9800!=y) || SH_MPC1211)
-	---help---
-	  There are two drivers for MFM/RLL/IDE disks.  Most people use just
-	  the new enhanced driver by itself.  This option however installs the
-	  old hard disk driver to control the primary IDE/disk interface in
-	  the system, leaving the new enhanced IDE driver to take care of only
-	  the 2nd/3rd/4th IDE interfaces.  Doing this will prevent you from
-	  having an IDE/ATAPI CD-ROM or tape drive connected to the primary
-	  IDE interface.  Choosing this option may be useful for older systems
-	  which have MFM/RLL/ESDI controller+drives at the primary port
-	  address (0x1f0), along with IDE drives at the secondary/3rd/4th port
-	  addresses.
-
-	  Normally, just say N here; you will then use the new driver for all
-	  4 interfaces.
-
-config BLK_DEV_HD_IDE98
-	bool "Use old disk-only driver on primary interface"
-	depends on X86 && X86_PC9800
+	depends on (X86 || SH_MPC1211)
 	---help---
 	  There are two drivers for MFM/RLL/IDE disks.  Most people use just
 	  the new enhanced driver by itself.  This option however installs the
--- diff/drivers/ide/Makefile	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/ide/Makefile	2004-05-27 18:34:16.000000000 +0100
@@ -29,7 +29,6 @@
 ide-core-$(CONFIG_IDE_ARM)		+= arm/ide_arm.o
 
 # built-in only drivers from legacy/
-ide-core-$(CONFIG_BLK_DEV_IDE_PC9800)	+= legacy/pc9800.o
 ide-core-$(CONFIG_BLK_DEV_BUDDHA)	+= legacy/buddha.o
 ide-core-$(CONFIG_BLK_DEV_FALCON_IDE)	+= legacy/falconide.o
 ide-core-$(CONFIG_BLK_DEV_GAYLE)	+= legacy/gayle.o
--- diff/drivers/ide/ide-disk.c	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/ide/ide-disk.c	2004-05-27 18:34:16.000000000 +0100
@@ -1329,6 +1329,41 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,
+			       sector_t *error_sector)
+{
+	ide_drive_t *drive = q->queuedata;
+	struct request *rq;
+	int ret;
+
+	if (!drive->wcache)
+		return 0;
+
+	rq = blk_get_request(q, WRITE, __GFP_WAIT);
+
+	memset(rq->cmd, 0, sizeof(rq->cmd));
+
+	if ((drive->id->cfs_enable_2 & 0x2400) == 0x2400)
+		rq->cmd[0] = WIN_FLUSH_CACHE_EXT;
+	else
+		rq->cmd[0] = WIN_FLUSH_CACHE;
+
+
+	rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER;
+	rq->buffer = rq->cmd;
+
+	ret = blk_execute_rq(q, disk, rq);
+
+	/*
+	 * if we failed and caller wants error offset, get it
+	 */
+	if (ret && error_sector)
+		*error_sector = ide_get_error_location(drive, rq->cmd);
+
+	blk_put_request(rq);
+	return ret;
+}
+
 /*
  * This is tightly woven into the driver->do_special can not touch.
  * DON'T do it again until a total personality rewrite is committed.
@@ -1357,16 +1392,10 @@
 	return 0;
 }
 
-/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
-#define ide_id_has_flush_cache(id)	((id)->cfs_enable_2 & 0x3000)
-
-/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */
-#define ide_id_has_flush_cache_ext(id)	\
-	(((id)->cfs_enable_2 & 0x2400) == 0x2400)
-
 static int write_cache (ide_drive_t *drive, int arg)
 {
 	ide_task_t args;
+	int err;
 
 	if (!ide_id_has_flush_cache(drive->id))
 		return 1;
@@ -1377,7 +1406,10 @@
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
 	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
 	args.handler				= &task_no_data_intr;
-	(void) ide_raw_taskfile(drive, &args, NULL);
+
+	err = ide_raw_taskfile(drive, &args, NULL);
+	if (err)
+		return err;
 
 	drive->wcache = arg;
 	return 0;
@@ -1558,6 +1590,7 @@
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long long capacity;
+	int barrier;
 
 	idedisk_add_settings(drive);
 
@@ -1690,6 +1723,27 @@
 
 	write_cache(drive, 1);
 
+	/*
+	 * decide if we can sanely support flushes and barriers on
+	 * this drive. unfortunately not all drives advertise FLUSH_CACHE
+	 * support even if they support it. So assume FLUSH_CACHE is there
+	 * always. LBA48 drives are newer, so expect it to flag support
+	 * properly. We can safely support FLUSH_CACHE on lba48, if capacity
+	 * doesn't exceed lba28
+	 */
+	barrier = 1;
+	if (drive->addressing == 1) {
+		barrier = ide_id_has_flush_cache(id);
+		if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id))
+			barrier = 0;
+	}
+
+	printk("%s: cache flushes %ssupported\n", drive->name, barrier ? "" : "not ");
+	if (barrier) {
+		blk_queue_ordered(drive->queue, 1);
+		blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush);
+	}
+
 #ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
 	if (drive->using_dma)
 		__ide_dma_queued_on(drive);
--- diff/drivers/ide/ide-io.c	2004-05-27 13:41:17.000000000 +0100
+++ source/drivers/ide/ide-io.c	2004-05-27 18:34:16.000000000 +0100
@@ -54,38 +54,73 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-/**
- *	ide_end_request		-	complete an IDE I/O
- *	@drive: IDE device for the I/O
- *	@uptodate: 
- *	@nr_sectors: number of sectors completed
- *
- *	This is our end_request wrapper function. We complete the I/O
- *	update random number input and dequeue the request, which if
- *	it was tagged may be out of order.
+static void ide_fill_flush_cmd(ide_drive_t *drive, struct request *rq)
+{
+	char *buf = rq->cmd;
+
+	/*
+	 * reuse cdb space for ata command
+	 */
+	memset(buf, 0, sizeof(rq->cmd));
+
+	rq->flags |= REQ_DRIVE_TASK | REQ_STARTED;
+	rq->buffer = buf;
+	rq->buffer[0] = WIN_FLUSH_CACHE;
+
+	if (ide_id_has_flush_cache_ext(drive->id))
+		rq->buffer[0] = WIN_FLUSH_CACHE_EXT;
+}
+
+/*
+ * preempt pending requests, and store this cache flush for immediate
+ * execution
  */
- 
-int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
+static struct request *ide_queue_flush_cmd(ide_drive_t *drive,
+					   struct request *rq, int post)
 {
-	struct request *rq;
-	unsigned long flags;
-	int ret = 1;
+	struct request *flush_rq = &HWGROUP(drive)->wrq;
 
-	spin_lock_irqsave(&ide_lock, flags);
-	rq = HWGROUP(drive)->rq;
+	/*
+	 * write cache disabled, just return barrier write immediately
+	 */
+	if (!drive->wcache)
+		return rq;
 
-	BUG_ON(!(rq->flags & REQ_STARTED));
+	ide_init_drive_cmd(flush_rq);
+	ide_fill_flush_cmd(drive, flush_rq);
 
-	if (!nr_sectors)
-		nr_sectors = rq->hard_cur_sectors;
+	flush_rq->special = rq;
+	flush_rq->nr_sectors = rq->nr_sectors;
+
+	if (!post) {
+		drive->doing_barrier = 1;
+		flush_rq->flags |= REQ_BAR_PREFLUSH;
+		blkdev_dequeue_request(rq);
+	} else
+		flush_rq->flags |= REQ_BAR_POSTFLUSH;
+
+	__elv_add_request(drive->queue, flush_rq, ELEVATOR_INSERT_FRONT, 0);
+	HWGROUP(drive)->rq = NULL;
+	return flush_rq;
+}
+
+static int __ide_end_request(ide_drive_t *drive, struct request *rq,
+			     int uptodate, int nr_sectors)
+{
+	int ret = 1;
+
+	BUG_ON(!(rq->flags & REQ_STARTED));
 
 	/*
 	 * if failfast is set on a request, override number of sectors and
 	 * complete the whole request right now
 	 */
-	if (blk_noretry_request(rq) && !uptodate)
+	if (blk_noretry_request(rq) && end_io_error(uptodate))
 		nr_sectors = rq->hard_nr_sectors;
 
+	if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
+		rq->errors = -EIO;
+
 	/*
 	 * decide whether to reenable DMA -- 3 is a random magic for now,
 	 * if we DMA timeout more than 3 times, just stay in PIO
@@ -97,14 +132,54 @@
 
 	if (!end_that_request_first(rq, uptodate, nr_sectors)) {
 		add_disk_randomness(rq->rq_disk);
-		if (!blk_rq_tagged(rq))
-			blkdev_dequeue_request(rq);
-		else
+
+		if (blk_rq_tagged(rq))
 			blk_queue_end_tag(drive->queue, rq);
-		HWGROUP(drive)->rq = NULL;
+
+		blkdev_dequeue_request(rq);
 		end_that_request_last(rq);
+		HWGROUP(drive)->rq = NULL;
 		ret = 0;
 	}
+
+	return ret;
+}
+
+/**
+ *	ide_end_request		-	complete an IDE I/O
+ *	@drive: IDE device for the I/O
+ *	@uptodate:
+ *	@nr_sectors: number of sectors completed
+ *
+ *	This is our end_request wrapper function. We complete the I/O
+ *	update random number input and dequeue the request, which if
+ *	it was tagged may be out of order.
+ */
+
+int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	if (!nr_sectors)
+		nr_sectors = rq->hard_cur_sectors;
+
+	if (!blk_barrier_rq(rq))
+		ret = __ide_end_request(drive, rq, uptodate, nr_sectors);
+	else {
+		struct request *flush_rq = &HWGROUP(drive)->wrq;
+
+		flush_rq->nr_sectors -= nr_sectors;
+		if (!flush_rq->nr_sectors) {
+			ide_queue_flush_cmd(drive, rq, 1);
+			ret = 0;
+		}
+	}
+
 	spin_unlock_irqrestore(&ide_lock, flags);
 	return ret;
 }
@@ -140,6 +215,113 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+/*
+ * FIXME: probably move this somewhere else, name is bad too :)
+ */
+u64 ide_get_error_location(ide_drive_t *drive, char *args)
+{
+	u32 high, low;
+	u8 hcyl, lcyl, sect;
+	u64 sector;
+
+	high = 0;
+	hcyl = args[5];
+	lcyl = args[4];
+	sect = args[3];
+
+	if (ide_id_has_flush_cache_ext(drive->id)) {
+		low = (hcyl << 16) | (lcyl << 8) | sect;
+		HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+		high = ide_read_24(drive);
+	} else {
+		u8 cur = HWIF(drive)->INB(IDE_SELECT_REG);
+		if (cur & 0x40)
+			low = (hcyl << 16) | (lcyl << 8) | sect;
+		else {
+			low = hcyl * drive->head * drive->sect;
+			low += lcyl * drive->sect;
+			low += sect - 1;
+		}
+	}
+
+	sector = ((u64) high << 24) | low;
+	return sector;
+}
+EXPORT_SYMBOL(ide_get_error_location);
+
+static void ide_complete_barrier(ide_drive_t *drive, struct request *rq,
+				 int error)
+{
+	struct request *real_rq = rq->special;
+	int good_sectors, bad_sectors;
+	sector_t sector;
+
+	if (!error) {
+		if (blk_barrier_postflush(rq)) {
+			/*
+			 * this completes the barrier write
+			 */
+			__ide_end_request(drive, real_rq, 1, real_rq->hard_nr_sectors);
+			drive->doing_barrier = 0;
+		} else {
+			/*
+			 * just indicate that we did the pre flush
+			 */
+			real_rq->flags |= REQ_BAR_PREFLUSH;
+			elv_requeue_request(drive->queue, real_rq);
+		}
+		/*
+		 * all is fine, return
+		 */
+		return;
+	}
+
+	/*
+	 * we need to end real_rq, but it's not on the queue currently.
+	 * put it back on the queue, so we don't have to special case
+	 * anything else for completing it
+	 */
+	if (!blk_barrier_postflush(rq))
+		elv_requeue_request(drive->queue, real_rq);
+
+	/*
+	 * drive aborted flush command, assume FLUSH_CACHE_* doesn't
+	 * work and disable barrier support
+	 */
+	if (error & ABRT_ERR) {
+		printk(KERN_ERR "%s: barrier support doesn't work\n", drive->name);
+		__ide_end_request(drive, real_rq, -EOPNOTSUPP, real_rq->hard_nr_sectors);
+		blk_queue_ordered(drive->queue, 0);
+		blk_queue_issue_flush_fn(drive->queue, NULL);
+	} else {
+		/*
+		 * find out what part of the request failed
+		 */
+		good_sectors = 0;
+		if (blk_barrier_postflush(rq)) {
+			sector = ide_get_error_location(drive, rq->buffer);
+
+			if ((sector >= real_rq->hard_sector) &&
+			    (sector < real_rq->hard_sector + real_rq->hard_nr_sectors))
+				good_sectors = sector - real_rq->hard_sector;
+		} else
+			sector = real_rq->hard_sector;
+
+		bad_sectors = real_rq->hard_nr_sectors - good_sectors;
+		if (good_sectors)
+			__ide_end_request(drive, real_rq, 1, good_sectors);
+		if (bad_sectors)
+			__ide_end_request(drive, real_rq, 0, bad_sectors);
+
+		printk(KERN_ERR "%s: failed barrier write: "
+				"sector=%Lx(good=%d/bad=%d)\n",
+				drive->name, (unsigned long long)sector,
+				good_sectors, bad_sectors);
+	}
+
+	drive->doing_barrier = 0;
+}
+
 /**
  *	ide_end_drive_cmd	-	end an explicit drive command
  *	@drive: command 
@@ -229,6 +411,10 @@
 
 	spin_lock_irqsave(&ide_lock, flags);
 	blkdev_dequeue_request(rq);
+
+	if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq))
+		ide_complete_barrier(drive, rq, err);
+
 	HWGROUP(drive)->rq = NULL;
 	end_that_request_last(rq);
 	spin_unlock_irqrestore(&ide_lock, flags);
@@ -715,6 +901,22 @@
 repeat:	
 	best = NULL;
 	drive = hwgroup->drive;
+
+	/*
+	 * drive is doing pre-flush, ordered write, post-flush sequence. even
+	 * though that is 3 requests, it must be seen as a single transaction.
+	 * we must not preempt this drive until that is complete
+	 */
+	if (drive->doing_barrier) {
+		/*
+		 * small race where queue could get replugged during
+		 * the 3-request flush cycle, just yank the plug since
+		 * we want it to finish asap
+		 */
+		blk_remove_plug(drive->queue);
+		return drive;
+	}
+
 	do {
 		if ((!drive->sleep || time_after_eq(jiffies, drive->sleep))
 		    && !elv_queue_empty(drive->queue)) {
@@ -882,6 +1084,13 @@
 		}
 
 		/*
+		 * if rq is a barrier write, issue pre cache flush if not
+		 * already done
+		 */
+		if (blk_barrier_rq(rq) && !blk_barrier_preflush(rq))
+			rq = ide_queue_flush_cmd(drive, rq, 0);
+
+		/*
 		 * Sanity: don't accept a request that isn't a PM request
 		 * if we are currently power managed. This is very important as
 		 * blk_stop_queue() doesn't prevent the elv_next_request()
@@ -900,6 +1109,10 @@
 			break;
 		}
 
+		/*
+		 * we can only queue read-write requests, so let the drive
+		 * queue drain before continuing with this command.
+		 */
 		if (!rq->bio && ata_pending_commands(drive))
 			break;
 
@@ -936,7 +1149,9 @@
  */
 void do_ide_request(request_queue_t *q)
 {
-	ide_do_request(q->queuedata, IDE_NO_IRQ);
+	ide_drive_t *drive = q->queuedata;
+
+	ide_do_request(HWGROUP(drive), IDE_NO_IRQ);
 }
 
 /*
@@ -1305,6 +1520,7 @@
 {
 	memset(rq, 0, sizeof(*rq));
 	rq->flags = REQ_DRIVE_CMD;
+	rq->ref_count = 1;
 }
 
 EXPORT_SYMBOL(ide_init_drive_cmd);
--- diff/drivers/ide/ide-probe.c	2004-05-19 22:11:40.000000000 +0100
+++ source/drivers/ide/ide-probe.c	2004-05-27 18:34:16.000000000 +0100
@@ -914,11 +914,15 @@
 	if (!q)
 		return 1;
 
-	q->queuedata = HWGROUP(drive);
+	q->queuedata = drive;
 	blk_queue_segment_boundary(q, 0xffff);
 
-	if (!hwif->rqsize)
-		hwif->rqsize = hwif->no_lba48 ? 256 : 65536;
+	if (!hwif->rqsize) {
+		if (hwif->max_rqsize)
+			hwif->rqsize = hwif->max_rqsize(drive);
+		else
+			hwif->rqsize = hwif->no_lba48 ? 256 : 65536;
+	}
 	if (hwif->rqsize < max_sectors)
 		max_sectors = hwif->rqsize;
 	blk_queue_max_sectors(q, max_sectors);
--- diff/drivers/ide/ide-proc.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/ide/ide-proc.c	2004-05-27 18:34:16.000000000 +0100
@@ -352,7 +352,6 @@
 		case ide_cy82c693:	name = "cy82c693";	break;
 		case ide_4drives:	name = "4drives";	break;
 		case ide_pmac:		name = "mac-io";	break;
-		case ide_pc9800:	name = "pc9800";	break;
 		default:		name = "(unknown)";	break;
 	}
 	len = sprintf(page, "%s\n", name);
--- diff/drivers/ide/pci/siimage.c	2004-05-19 22:11:41.000000000 +0100
+++ source/drivers/ide/pci/siimage.c	2004-05-27 18:34:16.000000000 +0100
@@ -203,13 +203,12 @@
 	else
 		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
 
-	if(is_sata(hwif))
-	{
-		if(strstr(drive->id->model, "Maxtor"))
+	if (is_sata(hwif)) {
+		if (strstr(drive->id->model, "Maxtor 4D060H3"))
 			return 3;
 		return 4;
 	}
-	
+
 	if ((scsc & 0x30) == 0x10)	/* 133 */
 		mode = 4;
 	else if ((scsc & 0x30) == 0x20)	/* 2xPCI */
@@ -1046,25 +1045,34 @@
 	hwif->mmio			= 2;
 }
 
-static int is_dev_seagate_sata(ide_drive_t *drive)
+/* TODO firmware versions should be added - eric */
+static const char * sil_blacklist [] = {
+	"ST320012AS",
+	"ST330013AS",
+	"ST340017AS",
+	"ST360015AS",
+	"ST380023AS",
+	"ST3120023AS",
+	"ST340014ASL",
+	"ST360014ASL",
+	"ST380011ASL",
+	"ST3120022ASL",
+	"ST3160021ASL",
+};
+
+static unsigned int siimage_sata_max_rqsize(ide_drive_t *drive)
 {
 	const char *s = &drive->id->model[0];
-	unsigned len;
+	unsigned int n;
 
-	if (!drive->present)
-		return 0;
-
-	len = strnlen(s, sizeof(drive->id->model));
-
-	if ((len > 4) && (!memcmp(s, "ST", 2))) {
-		if ((!memcmp(s + len - 2, "AS", 2)) ||
-		    (!memcmp(s + len - 3, "ASL", 3))) {
-			printk(KERN_INFO "%s: applying pessimistic Seagate "
-					 "errata fix\n", drive->name);
-			return 1;
+	for (n = 0; n < ARRAY_SIZE(sil_blacklist); n++)
+		if (!memcmp(sil_blacklist[n], s, strlen(sil_blacklist[n]))) {
+			printk(KERN_INFO "%s: applying Seagate errata fix\n",
+					 drive->name);
+			return 15;
 		}
-	}
-	return 0;
+
+	return 128;
 }
 
 /**
@@ -1087,9 +1095,10 @@
 	
 	hwif->hwif_data = 0;
 
-	hwif->rqsize = 128;
-	if (is_sata(hwif) && is_dev_seagate_sata(&hwif->drives[0]))
-		hwif->rqsize = 15;
+	if (is_sata(hwif) && (class_rev <= 0x01))
+		hwif->max_rqsize = siimage_sata_max_rqsize;
+	else
+		hwif->rqsize = 128;
 
 	if (pci_get_drvdata(dev) == NULL)
 		return;
--- diff/drivers/ieee1394/hosts.c	2004-05-19 22:11:42.000000000 +0100
+++ source/drivers/ieee1394/hosts.c	2004-05-27 18:34:16.000000000 +0100
@@ -187,6 +187,9 @@
 void hpsb_remove_host(struct hpsb_host *host)
 {
         host->is_shutdown = 1;
+
+	del_timer_sync(&host->delayed_reset);
+
         host->driver = &dummy_driver;
 
         highlevel_remove_host(host);
--- diff/drivers/input/Kconfig	2004-05-19 22:11:42.000000000 +0100
+++ source/drivers/input/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -41,9 +41,16 @@
 	  module will be called mousedev.
 
 config INPUT_MOUSEDEV_PSAUX
-	bool "Provide legacy /dev/psaux device" if EMBEDDED
+	bool "Provide legacy /dev/psaux device"
 	default y
 	depends on INPUT_MOUSEDEV
+	---help---
+	  Say Y here if you want your mouse also be accessible as char device
+	  10:1 - /dev/psaux. The data available through /dev/psaux is exactly
+	  the same as the data from /dev/input/mice.
+
+	  If unsure, say Y.
+
 
 config INPUT_MOUSEDEV_SCREEN_X
 	int "Horizontal screen resolution"
--- diff/drivers/input/evbug.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/evbug.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -35,7 +35,7 @@
 #include <linux/device.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Input driver event debug module"); 
+MODULE_DESCRIPTION("Input driver event debug module");
 MODULE_LICENSE("GPL");
 
 static char evbug_name[] = "evbug";
@@ -67,7 +67,7 @@
 static void evbug_disconnect(struct input_handle *handle)
 {
 	printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
-	
+
 	input_close_device(handle);
 
 	kfree(handle);
@@ -79,7 +79,7 @@
 };
 
 MODULE_DEVICE_TABLE(input, evbug_ids);
-	
+
 static struct input_handler evbug_handler = {
 	.event =	evbug_event,
 	.connect =	evbug_connect,
--- diff/drivers/input/evdev.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/evdev.c	2004-05-27 18:34:16.000000000 +0100
@@ -126,7 +126,7 @@
 	int i = iminor(inode) - EVDEV_MINOR_BASE;
 	int accept_err;
 
-	if (i >= EVDEV_MINORS || !evdev_table[i])
+	if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
 		return -ENODEV;
 
 	if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
@@ -175,7 +175,7 @@
 		return -EAGAIN;
 
 	retval = wait_event_interruptible(list->evdev->wait,
-		list->head != list->tail && list->evdev->exist);
+		list->head != list->tail || (!list->evdev->exist));
 
 	if (retval)
 		return retval;
@@ -220,7 +220,7 @@
 
 		case EVIOCGID:
 			return copy_to_user((void *) arg, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0;
-		
+
 		case EVIOCGKEYCODE:
 			if (get_user(t, ((int *) arg) + 0)) return -EFAULT;
 			if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
@@ -428,7 +428,7 @@
 
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor);
-	class_simple_device_add(input_class, 
+	class_simple_device_add(input_class,
 				MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
 				dev->dev, "event%d", minor);
 
--- diff/drivers/input/gameport/cs461x.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/gameport/cs461x.c	2004-05-27 18:34:16.000000000 +0100
@@ -1,8 +1,8 @@
 /*
-	The all defines and part of code (such as cs461x_*) are 
-	contributed from ALSA 0.5.8 sources. 
+	The all defines and part of code (such as cs461x_*) are
+	contributed from ALSA 0.5.8 sources.
 	See http://www.alsa-project.org/ for sources
-	
+
 	Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
 */
 
@@ -89,8 +89,8 @@
 #define JSIO_BXOE                               0x00000040
 #define JSIO_BYOE                               0x00000080
 
-/* 
-   The card initialization code is obfuscated; the module cs461x 
+/*
+   The card initialization code is obfuscated; the module cs461x
    need to be loaded after ALSA modules initialized and something
    played on the CS 4610 chip (see sources for details of CS4610
    initialization code from ALSA)
@@ -112,7 +112,7 @@
 #define BA1_DWORD_SIZE          (13 * 1024 + 512)
 #define BA1_MEMORY_COUNT        3
 
-/* 
+/*
    Only one CS461x card is still suppoted; the code requires
    redesign to avoid this limitatuion.
 */
@@ -163,7 +163,7 @@
 	if(port){
 	    gameport_unregister_port(port);
 	    kfree(port);
-	}    
+	}
 	if (ba0) iounmap(ba0);
 #ifdef CS461X_FULL_MAP
 	if (ba1.name.data0) iounmap(ba1.name.data0);
@@ -187,13 +187,13 @@
 static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
 	unsigned js1, js2, jst;
-	
+
 	js1 = cs461x_peekBA0(BA0_JSC1);
 	js2 = cs461x_peekBA0(BA0_JSC2);
 	jst = cs461x_peekBA0(BA0_JSPT);
-	
-	*buttons = (~jst >> 4) & 0x0F; 
-	
+
+	*buttons = (~jst >> 4) & 0x0F;
+
 	axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
 	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
 	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
@@ -228,7 +228,7 @@
 {
 	int rc;
 	struct gameport* port;
-	
+
 	rc = pci_enable_device(pdev);
 	if (rc) {
 		printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
@@ -240,7 +240,7 @@
 #ifdef CS461X_FULL_MAP
 	ba1_addr = pci_resource_start(pdev, 1);
 #endif
-	if (ba0_addr == 0 || ba0_addr == ~0 
+	if (ba0_addr == 0 || ba0_addr == ~0
 #ifdef CS461X_FULL_MAP
             || ba1_addr == 0 || ba1_addr == ~0
 #endif
@@ -281,7 +281,7 @@
 	memset(port, 0, sizeof(struct gameport));
 
 	pci_set_drvdata(pdev, port);
-	
+
 	port->open = cs461x_gameport_open;
 	port->trigger = cs461x_gameport_trigger;
 	port->read = cs461x_gameport_read;
@@ -310,7 +310,7 @@
 {
 	cs461x_free(pdev);
 }
-	
+
 static struct pci_driver cs461x_pci_driver = {
         .name =         "CS461x Gameport",
         .id_table =     cs461x_pci_tbl,
--- diff/drivers/input/gameport/emu10k1-gp.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/gameport/emu10k1-gp.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -48,7 +48,7 @@
 	int size;
 	char phys[32];
 };
-	
+
 static struct pci_device_id emu_tbl[] = {
 	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
 	{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
@@ -61,7 +61,7 @@
 {
 	int ioport, iolen;
 	struct emu *emu;
-        
+
 	if (pci_enable_device(pdev))
 		return -EBUSY;
 
--- diff/drivers/input/gameport/fm801-gp.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/gameport/fm801-gp.c	2004-05-27 18:34:16.000000000 +0100
@@ -111,7 +111,7 @@
 
 	pci_set_drvdata(pci, gp);
 
-	outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */ 
+	outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */
 
 	gameport_register_port(&gp->gameport);
 
--- diff/drivers/input/gameport/gameport.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/gameport/gameport.c	2004-05-27 18:34:16.000000000 +0100
@@ -168,7 +168,7 @@
 		return -1;
 
 	gameport->dev = dev;
-	
+
 	return 0;
 }
 
--- diff/drivers/input/gameport/lightning.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/gameport/lightning.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -106,7 +106,7 @@
 
 	result = 0;
 
-fail:	outb(L4_SELECT_ANALOG, L4_PORT);	
+fail:	outb(L4_SELECT_ANALOG, L4_PORT);
 	return result;
 }
 
@@ -126,7 +126,7 @@
 static int l4_getcal(int port, int *cal)
 {
 	int i, result = -1;
-	
+
 	outb(L4_SELECT_ANALOG, L4_PORT);
 	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
 
@@ -208,7 +208,7 @@
 
 	return 0;
 }
-	
+
 static int __init l4_init(void)
 {
 	int cal[4] = {255,255,255,255};
@@ -266,7 +266,7 @@
 
 			if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
 				l4_setcal(l4->port, cal);
-			
+
 			gameport_register_port(gameport);
 		}
 
--- diff/drivers/input/gameport/ns558.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/input/gameport/ns558.c	2004-05-27 18:34:16.000000000 +0100
@@ -12,18 +12,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -59,7 +59,7 @@
 	char phys[32];
 	char name[32];
 };
-	
+
 static LIST_HEAD(ns558_list);
 
 /*
@@ -116,7 +116,7 @@
 			i = 0;
 			goto out;
 		}
-/* 
+/*
  * And now find the number of mirrors of the port.
  */
 
@@ -292,7 +292,7 @@
 				release_region(port->gameport.io & ~(port->size - 1), port->size);
 				kfree(port);
 				break;
-		
+
 			default:
 				break;
 		}
--- diff/drivers/input/gameport/vortex.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/input/gameport/vortex.c	2004-05-27 18:34:16.000000000 +0100
@@ -83,7 +83,7 @@
 		axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
 		if (axes[i] == 0x1fff) axes[i] = -1;
 	}
-        
+
         return 0;
 }
 
@@ -122,7 +122,7 @@
 
 	vortex->gameport.driver = vortex;
 	vortex->gameport.fuzz = 64;
-	
+
 	vortex->gameport.read = vortex_read;
 	vortex->gameport.trigger = vortex_trigger;
 	vortex->gameport.cooked_read = vortex_cooked_read;
@@ -145,7 +145,7 @@
 	vortex->io = vortex->base + id->driver_data;
 
 	gameport_register_port(&vortex->gameport);
-	
+
 	printk(KERN_INFO "gameport at pci%s speed %d kHz\n",
 		pci_name(dev), vortex->gameport.speed);
 
--- diff/drivers/input/input.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/input.c	2004-05-27 18:34:16.000000000 +0100
@@ -106,7 +106,7 @@
 			}
 
 			break;
-		
+
 		case EV_ABS:
 
 			if (code > ABS_MAX || !test_bit(code, dev->absbit))
@@ -144,27 +144,27 @@
 			if (code > MSC_MAX || !test_bit(code, dev->mscbit))
 				return;
 
-			if (dev->event) dev->event(dev, type, code, value);	
-	
+			if (dev->event) dev->event(dev, type, code, value);
+
 			break;
 
 		case EV_LED:
-	
+
 			if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
 				return;
 
 			change_bit(code, dev->led);
-			if (dev->event) dev->event(dev, type, code, value);	
-	
+			if (dev->event) dev->event(dev, type, code, value);
+
 			break;
 
 		case EV_SND:
-	
+
 			if (code > SND_MAX || !test_bit(code, dev->sndbit))
 				return;
 
-			if (dev->event) dev->event(dev, type, code, value);	
-	
+			if (dev->event) dev->event(dev, type, code, value);
+
 			break;
 
 		case EV_REP:
@@ -181,7 +181,7 @@
 			break;
 	}
 
-	if (type != EV_SYN) 
+	if (type != EV_SYN)
 		dev->sync = 0;
 
 	if (dev->grab)
@@ -282,11 +282,11 @@
 		if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
 			if (id->id.vendor != dev->id.vendor)
 				continue;
-	
+
 		if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
 			if (id->id.product != dev->id.product)
 				continue;
-		
+
 		if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
 			if (id->id.version != dev->id.version)
 				continue;
@@ -351,11 +351,11 @@
 	}
 	if (in_interrupt()) {
 		printk(KERN_ERR "input.c: calling hotplug from interrupt\n");
-		return; 
+		return;
 	}
 	if (!current->fs->root) {
 		printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n");
-		return; 
+		return;
 	}
 	if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) {
 		printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n");
@@ -381,17 +381,17 @@
 
 	envp[i++] = scratch;
 	scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x",
-		dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1; 
-	
+		dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1;
+
 	if (dev->name) {
 		envp[i++] = scratch;
-		scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; 
+		scratch += sprintf(scratch, "NAME=%s", dev->name) + 1;
 	}
 
 	if (dev->phys) {
 		envp[i++] = scratch;
-		scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; 
-	}	
+		scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1;
+	}
 
 	SPRINTF_BIT_A(evbit, "EV=", EV_MAX);
 	SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY);
@@ -506,7 +506,7 @@
 		input_table[handler->minor >> 5] = handler;
 
 	list_add_tail(&handler->node, &input_handler_list);
-	
+
 	list_for_each_entry(dev, &input_dev_list, node)
 		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
 			if ((id = input_match_device(handler->id_table, dev)))
--- diff/drivers/input/joydev.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joydev.c	2004-05-27 18:34:16.000000000 +0100
@@ -1,12 +1,12 @@
 /*
  * Joystick device driver for the input driver suite.
  *
- * Copyright (c) 1999-2002 Vojtech Pavlik 
- * Copyright (c) 1999 Colin Van Dyke 
+ * Copyright (c) 1999-2002 Vojtech Pavlik
+ * Copyright (c) 1999 Colin Van Dyke
  *
  * 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 
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
 
@@ -34,7 +34,7 @@
 MODULE_LICENSE("GPL");
 
 #define JOYDEV_MINOR_BASE	0
-#define JOYDEV_MINORS		16	
+#define JOYDEV_MINORS		16
 #define JOYDEV_BUFFER_SIZE	64
 
 #define MSECS(t)	(1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
@@ -115,7 +115,7 @@
 
 		default:
 			return;
-	}  
+	}
 
 	event.time = MSECS(jiffies);
 
@@ -449,10 +449,10 @@
 	}
 
 	joydev_table[minor] = joydev;
-	
+
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor);
-	class_simple_device_add(input_class, 
+	class_simple_device_add(input_class,
 				MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
 				dev->dev, "js%d", minor);
 
@@ -466,7 +466,7 @@
 	joydev->exist = 0;
 
 	if (joydev->open)
-		input_close_device(handle);	
+		input_close_device(handle);
 	else
 		joydev_free(joydev);
 }
--- diff/drivers/input/joystick/Kconfig	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -22,7 +22,7 @@
 	  supports many extensions, including joysticks with throttle control,
 	  with rudders, additional hats and buttons compatible with CH
 	  Flightstick Pro, ThrustMaster FCS, 6 and 8 button gamepads, or
-	  Saitek Cyborg joysticks. 
+	  Saitek Cyborg joysticks.
 
 	  Please read the file <file:Documentation/input/joystick.txt> which
 	  contains more information.
@@ -35,7 +35,7 @@
 	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
 	help
 	  Say Y here if you have an FPGaming or MadCatz controller using the
-	  A3D protocol over the PC gameport. 
+	  A3D protocol over the PC gameport.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called a3d.
@@ -45,7 +45,7 @@
 	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
 	help
 	  Say Y here if you have a Logitech controller using the ADI
-	  protocol over the PC gameport. 
+	  protocol over the PC gameport.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called adi.
@@ -74,7 +74,7 @@
 	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
 	help
 	  Say Y here if you have a Gravis controller using the GrIP protocol
-	  over the PC gameport. 
+	  over the PC gameport.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called grip.
@@ -94,7 +94,7 @@
 	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
 	help
 	  Say Y here if you have a Guillemot joystick using a digital
-	  protocol over the PC gameport. 
+	  protocol over the PC gameport.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called guillemot.
@@ -124,7 +124,7 @@
 	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
 	help
 	  Say Y here if you have a ThrustMaster controller using the
-	  DirectConnect (BSP) protocol over the PC gameport. 
+	  DirectConnect (BSP) protocol over the PC gameport.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called tmdc.
@@ -137,7 +137,7 @@
 	select SERIO
 	help
 	  Say Y here if you have a Logitech WingMan Warrior joystick connected
-	  to your computer's serial port. 
+	  to your computer's serial port.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called warrior.
@@ -253,7 +253,7 @@
 	help
 	  Say Y here if you want to dump data from your joystick into the system
 	  log for debugging purposes. Say N if you are making a production
-	  configuration or aren't sure. 
+	  configuration or aren't sure.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called joydump.
--- diff/drivers/input/joystick/a3d.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/a3d.c	2004-05-27 18:34:16.000000000 +0100
@@ -39,8 +39,8 @@
 MODULE_DESCRIPTION("FP-Gaming Assasin 3D joystick driver");
 MODULE_LICENSE("GPL");
 
-#define A3D_MAX_START		400	/* 400 us */ 
-#define A3D_MAX_STROBE		60	/* 40 us */ 
+#define A3D_MAX_START		400	/* 400 us */
+#define A3D_MAX_STROBE		60	/* 40 us */
 #define A3D_DELAY_READ		3	/* 3 ms */
 #define A3D_MAX_LENGTH		40	/* 40*3 bits */
 #define A3D_REFRESH_TIME	HZ/50	/* 20 ms */
@@ -125,7 +125,7 @@
 
 			input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
 			input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
-			
+
 			input_report_key(dev, BTN_RIGHT,  data[2] & 1);
 			input_report_key(dev, BTN_LEFT,   data[3] & 2);
 			input_report_key(dev, BTN_MIDDLE, data[3] & 4);
@@ -201,7 +201,7 @@
 	int i;
 	for (i = 0; i < 4; i++)
 		axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
-	*buttons = a3d->buttons; 
+	*buttons = a3d->buttons;
 	return 0;
 }
 
@@ -216,7 +216,7 @@
 	if (mode != GAMEPORT_MODE_COOKED)
 		return -1;
 	if (!a3d->used++)
-		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);	
+		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
 	return 0;
 }
 
@@ -239,7 +239,7 @@
 {
 	struct a3d *a3d = dev->private;
 	if (!a3d->used++)
-		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);	
+		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
 	return 0;
 }
 
@@ -340,7 +340,7 @@
 		a3d->adc.open = a3d_adc_open;
 		a3d->adc.close = a3d_adc_close;
 		a3d->adc.cooked_read = a3d_adc_cooked_read;
-		a3d->adc.fuzz = 1; 
+		a3d->adc.fuzz = 1;
 
 		a3d->adc.name = a3d_names[a3d->mode];
 		a3d->adc.phys = a3d->adcphys;
--- diff/drivers/input/joystick/adi.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/input/joystick/adi.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -72,8 +72,8 @@
  */
 
 static char *adi_names[] = {	"WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
-				"WingMan Interceptor", "WingMan Formula", "WingMan GamePad", 
-				"WingMan Extreme Digital 3D", "WingMan GamePad Extreme", 
+				"WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
+				"WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
 				"WingMan GamePad USB", "Unknown Device %#x" };
 
 static char adi_wmgpe_abs[] =	{ ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
@@ -178,7 +178,7 @@
 
 /*
  * adi_move_bits() detects a possible 2-stream mode, and moves
- * the bits accordingly. 
+ * the bits accordingly.
  */
 
 static void adi_move_bits(struct adi_port *port, int length)
@@ -208,7 +208,7 @@
 	int i;
 	if ((adi->idx += count) > adi->ret) return 0;
 	for (i = 0; i < count; i++)
-		bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; 
+		bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i;
 	return bits;
 }
 
@@ -224,12 +224,12 @@
 	int i, t;
 
 	if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
-		return -1;	
+		return -1;
 
-	for (i = 0; i < adi->axes10; i++) 
+	for (i = 0; i < adi->axes10; i++)
 		input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
 
-	for (i = 0; i < adi->axes8; i++) 
+	for (i = 0; i < adi->axes8; i++)
 		input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
 
 	for (i = 0; i < adi->buttons && i < 63; i++) {
@@ -249,7 +249,7 @@
 
 	for (i = 63; i < adi->buttons; i++)
 		input_report_key(dev, *key++, adi_get_bits(adi, 1));
-	
+
 	input_sync(dev);
 
 	return 0;
@@ -294,7 +294,7 @@
 {
 	struct adi_port *port = dev->private;
 	if (!port->used++)
-		mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);	
+		mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
 	return 0;
 }
 
@@ -334,7 +334,7 @@
 		return;
 
 	if (adi->ret < (t = adi_get_bits(adi, 10))) {
-		printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); 
+		printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret);
 		return;
 	}
 
@@ -498,7 +498,7 @@
 
 	adi_init_digital(gameport);
 	adi_read_packet(port);
-	
+
 	if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
 		adi_move_bits(port, adi_get_bits(port->adi, 10));
 
--- diff/drivers/input/joystick/amijoy.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/amijoy.c	2004-05-27 18:34:16.000000000 +0100
@@ -46,7 +46,7 @@
 MODULE_LICENSE("GPL");
 
 static int amijoy[2] = { 0, 1 };
-static int amijoy_nargs;  
+static int amijoy_nargs;
 module_param_array_named(map, amijoy, uint, amijoy_nargs, 0);
 MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)");
 
--- diff/drivers/input/joystick/analog.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/input/joystick/analog.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -237,7 +237,7 @@
 
 	loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
 	timeout = ANALOG_MAX_TIME * port->speed;
-	
+
 	local_irq_save(flags);
 	gameport_trigger(gameport);
 	GET_TIME(now);
@@ -284,7 +284,7 @@
 
 	u = gameport_read(port->gameport);
 
-	if (!chf) { 
+	if (!chf) {
 		port->buttons = (~u >> 4) & 0xf;
 		return 0;
 	}
@@ -333,7 +333,7 @@
 		}
 	}
 
-	for (i = 0; i < 2; i++) 
+	for (i = 0; i < 2; i++)
 		if (port->analog[i].mask)
 			analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
 
@@ -348,7 +348,7 @@
 {
 	struct analog_port *port = dev->private;
 	if (!port->used++)
-		mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);	
+		mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
 	return 0;
 }
 
@@ -408,7 +408,7 @@
 
 static void analog_name(struct analog *analog)
 {
-	sprintf(analog->name, "Analog %d-axis %d-button", 
+	sprintf(analog->name, "Analog %d-axis %d-button",
 		hweight8(analog->mask & ANALOG_AXES_STD),
 		hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
 		hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
@@ -450,10 +450,10 @@
 	analog->dev.close = analog_close;
 	analog->dev.private = port;
 	analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	
+
 	for (i = j = 0; i < 4; i++)
 		if (analog->mask & (1 << i)) {
-			
+
 			t = analog_axes[j];
 			x = port->axes[i];
 			y = (port->axes[0] + port->axes[1]) >> 1;
@@ -481,8 +481,8 @@
 			j++;
 		}
 
-	for (i = j = 0; i < 3; i++) 
-		if (analog->mask & analog_exts[i]) 
+	for (i = j = 0; i < 3; i++)
+		if (analog->mask & analog_exts[i])
 			for (x = 0; x < 2; x++) {
 				t = analog_hats[j++];
 				set_bit(t, analog->dev.absbit);
@@ -517,7 +517,7 @@
 	else
 		printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
 		port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
-		port->speed > 10000 ? "M" : "k", 
+		port->speed > 10000 ? "M" : "k",
 		port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
 				    : (port->loop * 1000000) / port->speed);
 }
@@ -580,11 +580,11 @@
 
 		gameport_calibrate(port->gameport, port->axes, max);
 	}
-		
-	for (i = 0; i < 4; i++) 
+
+	for (i = 0; i < 4; i++)
 		port->initial[i] = port->axes[i];
 
-	return -!(analog[0].mask || analog[1].mask);	
+	return -!(analog[0].mask || analog[1].mask);
 }
 
 static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
@@ -606,7 +606,7 @@
 		msleep(ANALOG_MAX_TIME);
 		port->mask = (gameport_read(gameport) ^ t) & t & 0xf;
 		port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
-	
+
 		for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
 			if (!analog_cooked_read(port)) break;
 			msleep(ANALOG_MAX_TIME);
@@ -617,11 +617,11 @@
 		msleep(ANALOG_MAX_TIME);
 		t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
 		gameport_trigger(gameport);
-		while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++; 
+		while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++;
 		udelay(ANALOG_SAITEK_DELAY);
 		t = gameport_time(gameport, ANALOG_SAITEK_TIME);
 		gameport_trigger(gameport);
-		while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++; 
+		while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++;
 
 		if (v < (u >> 1)) { /* FIXME - more than one port */
 			analog_options[0] |= /* FIXME - more than one port */
@@ -721,7 +721,7 @@
 			if (!strcmp(analog_types[j].name, js[i])) {
 				analog_options[i] = analog_types[j].value;
 				break;
-			} 
+			}
 		if (analog_types[j].name) continue;
 
 		analog_options[i] = simple_strtoul(js[i], &end, 0);
--- diff/drivers/input/joystick/cobra.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/cobra.c	2004-05-27 18:34:16.000000000 +0100
@@ -72,7 +72,7 @@
 		r[i] = buf[i] = 0;
 		t[i] = COBRA_MAX_STROBE;
 	}
-	
+
 	local_irq_save(flags);
 
 	u = gameport_read(gameport);
@@ -140,14 +140,14 @@
 
 		}
 
-	mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);	
+	mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
 }
 
 static int cobra_open(struct input_dev *dev)
 {
 	struct cobra *cobra = dev->private;
 	if (!cobra->used++)
-		mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);	
+		mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
 	return 0;
 }
 
@@ -180,7 +180,7 @@
 
 	cobra->exists = cobra_read_packet(gameport, data);
 
-	for (i = 0; i < 2; i++) 
+	for (i = 0; i < 2; i++)
 		if ((cobra->exists >> i) & data[i] & 1) {
 			printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d"
 				" Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7);
@@ -205,7 +205,7 @@
 			cobra->dev[i].id.vendor = GAMEPORT_ID_VENDOR_CREATIVE;
 			cobra->dev[i].id.product = 0x0008;
 			cobra->dev[i].id.version = 0x0100;
-		
+
 			cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 			cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
 
--- diff/drivers/input/joystick/db9.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/db9.c	2004-05-27 18:34:16.000000000 +0100
@@ -14,14 +14,14 @@
 /*
  * 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 
+ * 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
@@ -95,7 +95,7 @@
 struct db9 {
 	struct input_dev dev[DB9_MAX_DEVICES];
 	struct timer_list timer;
-	struct pardevice *pd;	
+	struct pardevice *pd;
 	int mode;
 	int used;
 	char phys[2][32];
@@ -188,7 +188,7 @@
 }
 
 /*
- * db9_saturn_read_packet() reads whole saturn packet at connector 
+ * db9_saturn_read_packet() reads whole saturn packet at connector
  * and returns device identifier code.
  */
 static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char *data, int type, int powered)
@@ -481,16 +481,16 @@
 			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
 			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
 
-			parport_write_control(port, 0x0a); 
+			parport_write_control(port, 0x0a);
 
-			for (i = 0; i < 7; i++) { 
+			for (i = 0; i < 7; i++) {
 				data = parport_read_data(port);
-				parport_write_control(port, 0x02); 
-				parport_write_control(port, 0x0a); 
+				parport_write_control(port, 0x02);
+				parport_write_control(port, 0x0a);
 				input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2);
 				}
 
-			parport_write_control(port, 0x00); 
+			parport_write_control(port, 0x00);
 			break;
 		}
 
@@ -600,7 +600,7 @@
 
 		db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 		for (j = 0; j < db9_buttons[db9->mode]; j++)
-			set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); 
+			set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
 		for (j = 0; j < db9_num_axis[db9->mode]; j++) {
 			set_bit(db9_abs[j], db9->dev[i].absbit);
 			if (j < 2) {
@@ -635,7 +635,7 @@
 {
 	int i, j;
 
-	for (i = 0; i < 3; i++) 
+	for (i = 0; i < 3; i++)
 		if (db9_base[i]) {
 			for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++)
 				input_unregister_device(db9_base[i]->dev + j);
--- diff/drivers/input/joystick/gamecon.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/gamecon.c	2004-05-27 18:34:16.000000000 +0100
@@ -15,14 +15,14 @@
 /*
  * 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 
+ * 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
@@ -70,13 +70,13 @@
 #define GC_NES4		3
 #define GC_MULTI	4
 #define GC_MULTI2	5
-#define GC_N64		6	
+#define GC_N64		6
 #define GC_PSX		7
 
 #define GC_MAX		7
 
 #define GC_REFRESH_TIME	HZ/100
- 
+
 struct gc {
 	struct pardevice *pd;
 	struct input_dev dev[5];
@@ -104,7 +104,7 @@
 #define GC_N64_DELAY		133		/* delay between transmit request, and response ready (us) */
 #define GC_N64_REQUEST		0x1dd1111111ULL /* the request data command (encoded for 000000011) */
 #define GC_N64_DWS		3		/* delay between write segments (required for sound playback because of ISA DMA) */
-						/* GC_N64_DWS > 24 is known to fail */ 
+						/* GC_N64_DWS > 24 is known to fail */
 #define GC_N64_POWER_W		0xe2		/* power during write (transmit request) */
 #define GC_N64_POWER_R		0xfd		/* power during read */
 #define GC_N64_OUT		0x1d		/* output bits to the 4 pads */
@@ -113,8 +113,8 @@
 						/* than 123 us */
 #define GC_N64_CLOCK		0x02		/* clock bits for read */
 
-/* 
- * gc_n64_read_packet() reads an N64 packet. 
+/*
+ * gc_n64_read_packet() reads an N64 packet.
  * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
  */
 
@@ -224,7 +224,7 @@
  *	http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
  *	http://www.gamesx.com/controldata/psxcont/psxcont.htm
  *	ftp://milano.usal.es/pablo/
- *	
+ *
  */
 
 #define GC_PSX_DELAY	25		/* 25 usec */
@@ -331,13 +331,13 @@
 			s = gc_status_bit[i];
 
 			if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
-	
+
 				signed char axes[2];
 				axes[0] = axes[1] = 0;
 
 				for (j = 0; j < 8; j++) {
-					if (data[23 - j] & s) axes[0] |= 1 << j; 
-					if (data[31 - j] & s) axes[1] |= 1 << j; 
+					if (data[23 - j] & s) axes[0] |= 1 << j;
+					if (data[31 - j] & s) axes[1] |= 1 << j;
 				}
 
 				input_report_abs(dev + i, ABS_X,  axes[0]);
@@ -588,7 +588,7 @@
 				break;
 
 			case GC_PSX:
-				
+
 				psx = gc_psx_read_packet(gc, data);
 
 				switch(psx) {
@@ -629,7 +629,7 @@
 		}
 
 		sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i);
-		
+
                 gc->dev[i].name = gc_names[config[i + 1]];
 		gc->dev[i].phys = gc->phys[i];
                 gc->dev[i].id.bustype = BUS_PARPORT;
@@ -646,7 +646,7 @@
 		return NULL;
 	}
 
-	for (i = 0; i < 5; i++) 
+	for (i = 0; i < 5; i++)
 		if (gc->pads[0] & gc_status_bit[i]) {
 			input_register_device(gc->dev + i);
 			printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name);
@@ -675,7 +675,7 @@
 		if (gc_base[i]) {
 			for (j = 0; j < 5; j++)
 				if (gc_base[i]->pads[0] & gc_status_bit[j])
-					input_unregister_device(gc_base[i]->dev + j); 
+					input_unregister_device(gc_base[i]->dev + j);
 			parport_unregister_device(gc_base[i]->pd);
 		}
 }
--- diff/drivers/input/joystick/gf2k.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/input/joystick/gf2k.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -223,7 +223,7 @@
 {
 	struct gf2k *gf2k = dev->private;
 	if (!gf2k->used++)
-		mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);	
+		mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
 	return 0;
 }
 
@@ -324,7 +324,7 @@
 
 	for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
 		gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
-	      		  gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; 
+	      		  gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
 		gf2k->dev.absmin[gf2k_abs[i]] = 32;
 		gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
 		gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
--- diff/drivers/input/joystick/grip.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/grip.c	2004-05-27 18:34:16.000000000 +0100
@@ -48,8 +48,8 @@
 #define GRIP_STROBE_GPP		200	/* 200 us */
 #define GRIP_LENGTH_XT		4
 #define GRIP_STROBE_XT		64	/* 64 us */
-#define GRIP_MAX_CHUNKS_XT	10	
-#define GRIP_MAX_BITS_XT	30	
+#define GRIP_MAX_CHUNKS_XT	10
+#define GRIP_MAX_BITS_XT	30
 
 #define GRIP_REFRESH_TIME	HZ/50	/* 20 ms */
 
@@ -153,7 +153,7 @@
 				buf = (buf << 1) | (u >> 1);
 				t = strobe;
 				i++;
-			} else 
+			} else
 
 			if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
 				if (i == 20) {
--- diff/drivers/input/joystick/grip_mp.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/grip_mp.c	2004-05-27 18:34:16.000000000 +0100
@@ -69,7 +69,7 @@
 #define IO_MODE_FAST         0x0200           /* Used 3 data bits per gameport read     */
 #define IO_SLOT_CHANGE       0x0800           /* Multiport physical slot status changed */
 #define IO_DONE              0x1000           /* Multiport is done sending packets      */
-#define IO_RETRY             0x4000           /* Try again later to get packet          */ 
+#define IO_RETRY             0x4000           /* Try again later to get packet          */
 #define IO_RESET             0x8000           /* Force multiport to resend all packets  */
 
 /*
@@ -144,8 +144,8 @@
 /*
  * Gets a 28-bit packet from the multiport.
  *
- * After getting a packet successfully, commands encoded by sendcode may 
- * be sent to the multiport.  
+ * After getting a packet successfully, commands encoded by sendcode may
+ * be sent to the multiport.
  *
  * The multiport clock value is reflected in gameport bit B4.
  *
@@ -169,7 +169,7 @@
 
 	*packet = 0;
 	raw_data = gameport_read(gameport);
-	if (raw_data & 1)                          
+	if (raw_data & 1)
  		return IO_RETRY;
 
 	for (i = 0; i < 64; i++) {
@@ -183,11 +183,11 @@
 
 		if (raw_data & 0x31)
 			return IO_RESET;
-		gameport_trigger(gameport); 
+		gameport_trigger(gameport);
 
 		if (!poll_until(0x10, 0, 308, gameport, &raw_data))
 			return IO_RESET;
-	} else 
+	} else
 		return IO_RETRY;
 
 	/* Determine packet transfer mode and prepare for packet construction. */
@@ -195,7 +195,7 @@
 	if (raw_data & 0x20) {                 /* 3 data bits/read */
 		portvals |= raw_data >> 4;     /* Compare B4-B7 before & after trigger */
 
-		if (portvals != 0xb)           
+		if (portvals != 0xb)
 			return 0;
 		data_mask = 7;
 		bits_per_read = 3;
@@ -221,7 +221,7 @@
 			return IO_RESET;
 	}
 
-	if (raw_data)                            
+	if (raw_data)
 		return IO_RESET;
 
 	/* If 3 bits/read used, drop from 30 bits to 28. */
@@ -231,7 +231,7 @@
 		pkt = (pkt >> 2) | 0xf0000000;
 	}
 
-	if (bit_parity(pkt) == 1) 
+	if (bit_parity(pkt) == 1)
 		return IO_RESET;
 
 	/* Acknowledge packet receipt */
@@ -251,10 +251,10 @@
 
         /* Return if we just wanted the packet or multiport wants to send more */
 
-	*packet = pkt;	                             
+	*packet = pkt;
 	if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))
 		return IO_GOT_PACKET;
-	
+
 	if (pkt & PACKET_MP_MORE)
 		return IO_GOT_PACKET | IO_RETRY;
 
@@ -277,7 +277,7 @@
 		if (!poll_until(0x30, 0, 193, gameport, &raw_data))
 			return IO_GOT_PACKET | IO_RESET;
 
-		if (raw_data & 1)   
+		if (raw_data & 1)
 			return IO_GOT_PACKET | IO_RESET;
 
 		if (sendcode & 1)
@@ -429,19 +429,19 @@
 			strange_code = joytype;
 		}
 	}
-	return flags;  
+	return flags;
 }
 
 /*
  * Returns true if all multiport slot states appear valid.
  */
- 
+
 static int slots_valid(struct grip_mp *grip)
 {
 	int flags, slot, invalid = 0, active = 0;
 
 	flags = get_and_decode_packet(grip, 0);
-	if (!(flags & IO_GOT_PACKET))          
+	if (!(flags & IO_GOT_PACKET))
 		return 0;
 
 	for (slot = 0; slot < 4; slot++) {
@@ -463,7 +463,7 @@
  * Returns whether the multiport was placed into digital mode and
  * able to communicate its state successfully.
  */
- 
+
 static int multiport_init(struct grip_mp *grip)
 {
 	int dig_mode, initialized = 0, tries = 0;
@@ -481,7 +481,7 @@
 		dbg("multiport_init(): unable to achieve digital mode.\n");
 		return 0;
 	}
-	
+
 	/* Get packets, store multiport state, and check state's validity */
 	for (tries = 0; tries < 4096; tries++) {
 		if ( slots_valid(grip) ) {
@@ -520,9 +520,9 @@
 }
 
 /*
- * Get the multiport state.  
+ * Get the multiport state.
  */
- 
+
 static void get_and_report_mp_state(struct grip_mp *grip)
 {
 	int i, npkts, flags;
@@ -538,7 +538,7 @@
 			break;
 	}
 
-	for (i = 0; i < 4; i++)      
+	for (i = 0; i < 4; i++)
 		if (grip->dirty[i])
 			report_slot(grip, i);
 }
@@ -546,7 +546,7 @@
 /*
  * Called when a joystick device file is opened
  */
- 
+
 static int grip_open(struct input_dev *dev)
 {
 	struct grip_mp *grip = dev->private;
@@ -607,7 +607,7 @@
 /*
  * Repeatedly polls the multiport and generates events.
  */
- 
+
 static void grip_timer(unsigned long private)
 {
 	struct grip_mp *grip = (void*) private;
--- diff/drivers/input/joystick/guillemot.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/guillemot.c	2004-05-27 18:34:16.000000000 +0100
@@ -45,7 +45,7 @@
 #define GUILLEMOT_MAX_LENGTH	17	/* 17 bytes */
 #define GUILLEMOT_REFRESH_TIME	HZ/50	/* 20 ms */
 
-static short guillemot_abs_pad[] = 
+static short guillemot_abs_pad[] =
 	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
 
 static short guillemot_btn_pad[] =
@@ -160,7 +160,7 @@
 {
 	struct guillemot *guillemot = dev->private;
 	if (!guillemot->used++)
-		mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);	
+		mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
 	return 0;
 }
 
@@ -211,7 +211,7 @@
 	if (!guillemot_type[i].name) {
 		printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
 			gameport->phys, data[12], data[13], data[11], data[14], data[15]);
-		goto fail2;	
+		goto fail2;
 	}
 
 	sprintf(guillemot->phys, "%s/input0", gameport->phys);
@@ -237,7 +237,7 @@
 		guillemot->dev.absmax[t] = 255;
 	}
 
-	if (guillemot->type->hat) 
+	if (guillemot->type->hat)
 		for (i = 0; i < 2; i++) {
 			t = ABS_HAT0X + i;
 			set_bit(t, guillemot->dev.absbit);
--- diff/drivers/input/joystick/iforce/Kconfig	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/iforce/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -17,7 +17,7 @@
 	depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB
 	help
 	  Say Y here if you have an I-Force joystick or steering wheel
-	  connected to your USB port. 
+	  connected to your USB port.
 
 config JOYSTICK_IFORCE_232
 	bool "I-Force Serial joysticks and wheels"
--- diff/drivers/input/joystick/iforce/Makefile	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/iforce/Makefile	2004-05-27 18:34:16.000000000 +0100
@@ -7,14 +7,14 @@
 # Goal definition
 iforce-objs	:= iforce-ff.o iforce-main.o iforce-packets.o
 
-obj-$(CONFIG_JOYSTICK_IFORCE)	+= iforce.o 
+obj-$(CONFIG_JOYSTICK_IFORCE)	+= iforce.o
 
 ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
-	iforce-objs += iforce-serio.o 
+	iforce-objs += iforce-serio.o
 endif
 
 ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
-	iforce-objs += iforce-usb.o 
+	iforce-objs += iforce-usb.o
 endif
 
 EXTRA_CFLAGS = -Werror-implicit-function-declaration
--- diff/drivers/input/joystick/iforce/iforce-ff.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/iforce/iforce-ff.c	2004-05-27 18:34:16.000000000 +0100
@@ -195,7 +195,7 @@
 }
 
 /*
- * Analyse the changes in an effect, and tell if we need to send an condition 
+ * Analyse the changes in an effect, and tell if we need to send an condition
  * parameter packet
  */
 static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new)
@@ -372,7 +372,7 @@
 	int core_err = 0;
 
 	if (!is_update || need_period_modifier(iforce, effect)) {
-		param1_err = make_period_modifier(iforce, mod1_chunk, 
+		param1_err = make_period_modifier(iforce, mod1_chunk,
 			is_update,
 			effect->u.periodic.magnitude, effect->u.periodic.offset,
 			effect->u.periodic.period, effect->u.periodic.phase);
--- diff/drivers/input/joystick/iforce/iforce-main.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/iforce/iforce-main.c	2004-05-27 18:34:16.000000000 +0100
@@ -166,7 +166,7 @@
 	else {
 		/* We want to update an effect */
 		if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES;
-		
+
 		/* Parameter type cannot be updated */
 		if (effect->type != iforce->core_effects[effect->id].effect.type)
 			return -EINVAL;
@@ -273,7 +273,7 @@
 
 		if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
 			current->pid == iforce->core_effects[i].owner) {
-			
+
 			/* Stop effect */
 			input_report_ff(dev, i, 0);
 
--- diff/drivers/input/joystick/iforce/iforce-packets.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/iforce/iforce-packets.c	2004-05-27 18:34:16.000000000 +0100
@@ -56,7 +56,7 @@
 	int empty;
 	int head, tail;
 	unsigned long flags;
-			
+
 /*
  * Update head and tail of xmit buffer
  */
@@ -108,7 +108,7 @@
 		break;
 #endif
 #ifdef CONFIG_JOYSTICK_IFORCE_USB
-		case IFORCE_USB: 
+		case IFORCE_USB:
 
 		if (iforce->usbdev && empty &&
 			!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
--- diff/drivers/input/joystick/iforce/iforce-serio.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/iforce/iforce-serio.c	2004-05-27 18:34:16.000000000 +0100
@@ -62,7 +62,7 @@
 		cs ^= iforce->xmit.buf[iforce->xmit.tail];
 		XMIT_INC(iforce->xmit.tail, 1);
 	}
-	
+
 	serio_write(iforce->serio, cs);
 
 	if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
--- diff/drivers/input/joystick/iforce/iforce.h	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/iforce/iforce.h	2004-05-27 18:34:16.000000000 +0100
@@ -141,7 +141,7 @@
 	struct circ_buf xmit;
 	unsigned char xmit_data[XMIT_SIZE];
 	long xmit_flags[1];
-	
+
 					/* Force Feedback */
 	wait_queue_head_t wait;
 	struct resource device_memory;
--- diff/drivers/input/joystick/interact.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/interact.c	2004-05-27 18:34:16.000000000 +0100
@@ -63,7 +63,7 @@
 	char phys[32];
 };
 
-static short interact_abs_hhfx[] = 
+static short interact_abs_hhfx[] =
 	{ ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
 static short interact_abs_pp8d[] =
 	{ ABS_X, ABS_Y, -1 };
@@ -166,7 +166,7 @@
 			case INTERACT_TYPE_PP8D:
 
 				for (i = 0; i < 2; i++)
-					input_report_abs(dev, interact_abs_pp8d[i], 
+					input_report_abs(dev, interact_abs_pp8d[i],
 						((data[0] >> ((i << 1) + 20)) & 1)  - ((data[0] >> ((i << 1) + 21)) & 1));
 
 				for (i = 0; i < 8; i++)
@@ -190,7 +190,7 @@
 {
 	struct interact *interact = dev->private;
 	if (!interact->used++)
-		mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);	
+		mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
 	return 0;
 }
 
@@ -242,7 +242,7 @@
 	if (!interact_type[i].length) {
 		printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n",
 			gameport->phys, i, data[0], data[1], data[2]);
-		goto fail2;	
+		goto fail2;
 	}
 
 	sprintf(interact->phys, "%s/input0", gameport->phys);
--- diff/drivers/input/joystick/joydump.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/joydump.c	2004-05-27 18:34:16.000000000 +0100
@@ -12,18 +12,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -63,7 +63,7 @@
 		printk(KERN_INFO "joydump: | Raw mode not available - trying cooked.    |\n");
 
 		if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
-			
+
 			printk(KERN_INFO "joydump: | Cooked not available either. Failing.      |\n");
 			printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
 			return;
--- diff/drivers/input/joystick/magellan.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/magellan.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  *  Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -159,7 +159,7 @@
 
 	memset(magellan, 0, sizeof(struct magellan));
 
-	magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	for (i = 0; i < 9; i++)
 		set_bit(magellan_buttons[i], magellan->dev.keybit);
@@ -181,7 +181,7 @@
 	magellan->dev.id.vendor = SERIO_MAGELLAN;
 	magellan->dev.id.product = 0x0001;
 	magellan->dev.id.version = 0x0100;
-	
+
 	serio->private = magellan;
 
 	if (serio_open(serio, dev)) {
--- diff/drivers/input/joystick/sidewinder.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/sidewinder.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -176,19 +176,19 @@
 				buf[i] = v >> 5;		/* Store it */
 			i++;					/* Advance index */
 			bitout = strobe;			/* Extend timeout for next bit */
-		} 
+		}
 
 		if (kick && (~v & u & 0x01)) {			/* Falling edge on axis 0 */
 			sched = kick;				/* Schedule second trigger */
 			kick = 0;				/* Don't schedule next time on falling edge */
 			pending = 1;				/* Mark schedule */
-		} 
+		}
 
 		if (pending && sched < 0 && (i > -SW_END)) {	/* Second trigger time */
 			gameport_trigger(gameport);		/* Trigger */
 			bitout = start;				/* Long bit timeout */
 			pending = 0;				/* Unmark schedule */
-			timeout = 0;				/* Switch from global to bit timeouts */ 
+			timeout = 0;				/* Switch from global to bit timeouts */
 		}
 	}
 
@@ -482,14 +482,14 @@
 	sw_read_packet(sw->gameport, buf, SW_LENGTH, i);			/* Read ID packet, this initializes the stick */
 
 	sw->fail = SW_FAIL;
-	
+
 	return -1;
 }
 
 static void sw_timer(unsigned long private)
 {
 	struct sw *sw = (void *) private;
-	
+
 	sw->reads++;
 	if (sw_read(sw)) sw->bads++;
 	mod_timer(&sw->timer, jiffies + SW_REFRESH);
@@ -653,7 +653,7 @@
 				case 60:
 					sw->number++;
 				case 45:				/* Ambiguous packet length */
-					if (j <= 40) {			/* ID length less or eq 40 -> FSP */	
+					if (j <= 40) {			/* ID length less or eq 40 -> FSP */
 				case 43:
 						sw->type = SW_ID_FSP;
 						break;
--- diff/drivers/input/joystick/spaceball.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/spaceball.c	2004-05-27 18:34:16.000000000 +0100
@@ -15,18 +15,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  *  Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -59,8 +59,8 @@
 
 static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY };
 static char *spaceball_names[] = {
-	"?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B", 
-	"SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController", 
+	"?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B",
+	"SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController",
 	"SpaceTec SpaceBall 3003C", "SpaceTec SpaceBall 4000FLX", "SpaceTec SpaceBall 4000FLX Lefty" };
 
 /*
@@ -96,7 +96,7 @@
 		case 'D':					/* Ball data */
 			if (spaceball->idx != 15) return;
 			for (i = 0; i < 6; i++)
-				input_report_abs(dev, spaceball_axes[i], 
+				input_report_abs(dev, spaceball_axes[i],
 					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
 			break;
 
@@ -216,7 +216,7 @@
 		return;
 	memset(spaceball, 0, sizeof(struct spaceball));
 
-	spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	switch (id) {
 		case SPACEBALL_4000FLX:
@@ -224,7 +224,7 @@
 			spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9);
 			spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE);
 		default:
-			spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) 
+			spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4)
 				| BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8);
 		case SPACEBALL_3003C:
 			spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8);
@@ -251,7 +251,7 @@
 	spaceball->dev.id.vendor = SERIO_SPACEBALL;
 	spaceball->dev.id.product = id;
 	spaceball->dev.id.version = 0x0100;
-	
+
 	serio->private = spaceball;
 
 	if (serio_open(serio, dev)) {
--- diff/drivers/input/joystick/spaceorb.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/spaceorb.c	2004-05-27 18:34:16.000000000 +0100
@@ -2,7 +2,7 @@
  * $Id: spaceorb.c,v 1.15 2002/01/22 20:29:19 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
- * 
+ *
  *  Based on the work of:
  *  	David Thompson
  */
@@ -14,18 +14,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  *  Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -67,7 +67,7 @@
 static unsigned char spaceorb_xor[] = "SpaceWare";
 
 static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
-		"Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; 
+		"Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" };
 
 /*
  * spaceorb_process_packet() decodes packets the driver receives from the
@@ -99,7 +99,7 @@
 
 		case 'D':				/* Ball + button data */
 			if (spaceorb->idx != 12) return;
-			for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i]; 
+			for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i];
 			axes[0] = ( data[2]	 << 3) | (data[ 3] >> 4);
 			axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
 			axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
@@ -174,7 +174,7 @@
 		return;
 	memset(spaceorb, 0, sizeof(struct spaceorb));
 
-	spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	for (i = 0; i < 6; i++)
 		set_bit(spaceorb_buttons[i], spaceorb->dev.keybit);
@@ -198,7 +198,7 @@
 	spaceorb->dev.id.vendor = SERIO_SPACEORB;
 	spaceorb->dev.id.product = 0x0001;
 	spaceorb->dev.id.version = 0x0100;
-	
+
 	serio->private = spaceorb;
 
 	if (serio_open(serio, dev)) {
--- diff/drivers/input/joystick/stinger.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/stinger.c	2004-05-27 18:34:16.000000000 +0100
@@ -147,7 +147,7 @@
 
 	memset(stinger, 0, sizeof(struct stinger));
 
-	stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 	stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \
 					   BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \
 					   BIT(BTN_START) | BIT(BTN_SELECT);
@@ -164,8 +164,8 @@
 	stinger->dev.id.version = 0x0100;
 
 	for (i = 0; i < 2; i++) {
-		stinger->dev.absmax[ABS_X+i] =  64;	
-		stinger->dev.absmin[ABS_X+i] = -64;	
+		stinger->dev.absmax[ABS_X+i] =  64;
+		stinger->dev.absmin[ABS_X+i] = -64;
 		stinger->dev.absflat[ABS_X+i] = 4;
 	}
 
--- diff/drivers/input/joystick/tmdc.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/tmdc.c	2004-05-27 18:34:16.000000000 +0100
@@ -4,7 +4,7 @@
  *  Copyright (c) 1998-2001 Vojtech Pavlik
  *
  *   Based on the work of:
- *	Trystan Larey-Williams 
+ *	Trystan Larey-Williams
  */
 
 /*
@@ -14,18 +14,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -58,7 +58,7 @@
 #define TMDC_BYTE_REV		11
 #define TMDC_BYTE_DEF		12
 
-#define TMDC_ABS		7	
+#define TMDC_ABS		7
 #define TMDC_ABS_HAT		4
 #define TMDC_BTN		16
 
@@ -104,7 +104,7 @@
 	unsigned char btno[2][4];
 	int used;
 	int reads;
-	int bads;	
+	int bads;
 	unsigned char exists;
 };
 
@@ -127,7 +127,7 @@
 
 	local_irq_save(flags);
 	gameport_trigger(gameport);
-	
+
 	w = gameport_read(gameport) >> 4;
 
 	do {
@@ -148,7 +148,7 @@
 				}
 				data[k][i[k]] |= (~v & 1) << (j[k]++ - 1);	/* Data bit */
 			}
-			t[k]--; 
+			t[k]--;
 		}
 	} while (t[0] > 0 || t[1] > 0);
 
@@ -175,7 +175,7 @@
 		bad = 1;
 	else
 
-	for (j = 0; j < 2; j++) 
+	for (j = 0; j < 2; j++)
 		if (r & (1 << j) & tmdc->exists) {
 
 			if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) {
@@ -227,7 +227,7 @@
 {
 	struct tmdc *tmdc = dev->private;
 	if (!tmdc->used++)
-		mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);	
+		mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
 	return 0;
 }
 
@@ -356,7 +356,7 @@
 	struct tmdc *tmdc = gameport->private;
 	int i;
 	for (i = 0; i < 2; i++)
-		if (tmdc->exists & (1 << i)) 
+		if (tmdc->exists & (1 << i))
 			input_unregister_device(tmdc->dev + i);
 	gameport_close(gameport);
 	kfree(tmdc);
--- diff/drivers/input/joystick/turbografx.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/turbografx.c	2004-05-27 18:34:16.000000000 +0100
@@ -14,18 +14,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -65,7 +65,7 @@
 
 #define TGFX_TRIGGER		0x08
 #define TGFX_UP			0x10
-#define TGFX_DOWN		0x20	
+#define TGFX_DOWN		0x20
 #define TGFX_LEFT		0x40
 #define TGFX_RIGHT		0x80
 
@@ -126,7 +126,7 @@
         if (!tgfx->used++) {
 		parport_claim(tgfx->pd);
 		parport_write_control(tgfx->pd->port, 0x04);
-                mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); 
+                mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
 	}
         return 0;
 }
@@ -173,7 +173,7 @@
 	memset(tgfx, 0, sizeof(struct tgfx));
 
 	tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-		
+
 	parport_put_port(pp);
 
 	if (!tgfx->pd) {
@@ -210,7 +210,7 @@
 			tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
 
 			for (j = 0; j < config[i+1]; j++)
-				set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); 
+				set_bit(tgfx_buttons[j], tgfx->dev[i].keybit);
 
 			tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1;
 			tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1;
@@ -225,7 +225,7 @@
 		kfree(tgfx);
 		return NULL;
         }
-		
+
 	return tgfx;
 }
 
@@ -245,7 +245,7 @@
 {
 	int i, j;
 
-	for (i = 0; i < 3; i++) 
+	for (i = 0; i < 3; i++)
 		if (tgfx_base[i]) {
 			for (j = 0; j < 7; j++)
 				if (tgfx_base[i]->sticks & (1 << j))
--- diff/drivers/input/joystick/twidjoy.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/twidjoy.c	2004-05-27 18:34:16.000000000 +0100
@@ -58,6 +58,9 @@
 #include <linux/serio.h>
 #include <linux/init.h>
 
+MODULE_DESCRIPTION("Handykey Twiddler keyboard as a joystick driver");
+MODULE_LICENSE("GPL");
+
 /*
  * Constants.
  */
@@ -142,7 +145,7 @@
  * packet processing routine.
  */
 
-static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struc pt_regs *regs)
+static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
 	struct twidjoy *twidjoy = serio->private;
 
@@ -153,7 +156,7 @@
 	if ((data & 0x80) == 0)
 		twidjoy->idx = 0;	/* this byte starts a new packet */
 	else if (twidjoy->idx == 0)
-		return;			/* wrong MSB -- ignore this byte */
+		return IRQ_HANDLED;	/* wrong MSB -- ignore this byte */
 
 	if (twidjoy->idx < TWIDJOY_MAX_LENGTH)
 		twidjoy->data[twidjoy->idx++] = data;
@@ -163,7 +166,7 @@
 		twidjoy->idx = 0;
 	}
 
-	return;
+	return IRQ_HANDLED;
 }
 
 /*
@@ -208,7 +211,7 @@
 	twidjoy->dev.id.product = 0x0001;
 	twidjoy->dev.id.version = 0x0100;
 
-	twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	for (bp = twidjoy_buttons; bp->bitmask; bp++) {
 		for (i = 0; i < bp->bitmask; i++)
@@ -218,8 +221,8 @@
 	twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
 
 	for (i = 0; i < 2; i++) {
-		twidjoy->dev.absmax[ABS_X+i] =  50;	
-		twidjoy->dev.absmin[ABS_X+i] = -50;	
+		twidjoy->dev.absmax[ABS_X+i] =  50;
+		twidjoy->dev.absmin[ABS_X+i] = -50;
 
 		/* TODO: arndt 20010708: Are these values appropriate? */
 		twidjoy->dev.absfuzz[ABS_X+i] = 4;
--- diff/drivers/input/joystick/warrior.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/joystick/warrior.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * This program is free warftware; 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 
+ * 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
- * 
+ *
  *  Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -44,7 +44,7 @@
  */
 
 #define WARRIOR_MAX_LENGTH	16
-static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; 
+static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 };
 static char *warrior_name = "Logitech WingMan Warrior";
 
 /*
@@ -114,7 +114,7 @@
 		warrior->data[warrior->idx++] = data;
 
 	if (warrior->idx == warrior->len) {
-		if (warrior->idx) warrior_process_packet(warrior, regs);	
+		if (warrior->idx) warrior_process_packet(warrior, regs);
 		warrior->idx = 0;
 		warrior->len = 0;
 	}
@@ -152,7 +152,7 @@
 
 	memset(warrior, 0, sizeof(struct warrior));
 
-	warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);	
+	warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
 	warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
 	warrior->dev.relbit[0] = BIT(REL_DIAL);
 	warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
@@ -168,24 +168,24 @@
 	warrior->dev.id.version = 0x0100;
 
 	for (i = 0; i < 2; i++) {
-		warrior->dev.absmax[ABS_X+i] = -64;	
-		warrior->dev.absmin[ABS_X+i] =  64;	
-		warrior->dev.absflat[ABS_X+i] = 8;	
+		warrior->dev.absmax[ABS_X+i] = -64;
+		warrior->dev.absmin[ABS_X+i] =  64;
+		warrior->dev.absflat[ABS_X+i] = 8;
 	}
 
-	warrior->dev.absmax[ABS_THROTTLE] = -112;	
-	warrior->dev.absmin[ABS_THROTTLE] =  112;	
+	warrior->dev.absmax[ABS_THROTTLE] = -112;
+	warrior->dev.absmin[ABS_THROTTLE] =  112;
 
 	for (i = 0; i < 2; i++) {
-		warrior->dev.absmax[ABS_HAT0X+i] = -1;	
-		warrior->dev.absmin[ABS_HAT0X+i] =  1;	
+		warrior->dev.absmax[ABS_HAT0X+i] = -1;
+		warrior->dev.absmin[ABS_HAT0X+i] =  1;
 	}
 
 	warrior->dev.private = warrior;
-	
+
 	serio->private = warrior;
 
-	if (serio_open(serio, dev)) { 
+	if (serio_open(serio, dev)) {
 		kfree(warrior);
 		return;
 	}
--- diff/drivers/input/keyboard/98kbd.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/keyboard/98kbd.c	2004-05-27 18:34:16.000000000 +0100
@@ -12,18 +12,18 @@
 /*
  * 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 
+ * 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/delay.h>
@@ -43,7 +43,7 @@
 #define KBD98_KEY	0x7f
 #define KBD98_RELEASE	0x80
 
-static unsigned char kbd98_keycode[256] = {	 
+static unsigned char kbd98_keycode[256] = {
 	  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 43, 14, 15,
 	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 41, 26, 28, 30, 31, 32,
 	 33, 34, 35, 36, 37, 38, 39, 40, 27, 44, 45, 46, 47, 48, 49, 50,
@@ -109,8 +109,8 @@
 	struct jis_kbd_conv jis[16];
 };
 
-void kbd98_interrupt(struct serio *serio, unsigned char data,
-			unsigned int flags, struct pt_regs *regs)
+irqreturn_t kbd98_interrupt(struct serio *serio, unsigned char data,
+			    unsigned int flags, struct pt_regs *regs)
 {
 	struct kbd98 *kbd98 = serio->private;
 	unsigned char scancode, keycode;
@@ -119,15 +119,15 @@
 	switch (data) {
 		case KBD98_RET_ACK:
 			kbd98->ack = 1;
-			return;
+			goto out;
 		case KBD98_RET_NAK:
 			kbd98->ack = -1;
-			return;
+			goto out;
 	}
 
 	if (kbd98->cmdcnt) {
 		kbd98->cmdbuf[--kbd98->cmdcnt] = data;
-		return;
+		goto out;
 	}
 
 	scancode = data & KBD98_KEY;
@@ -164,7 +164,7 @@
 
 			keycode = kbd98->jis[i].emul[kbd98->shift].keycode;
 			if (keycode == KBD98_KEY_NULL)
-				return;
+				break;
 
 			if (press) {
 				kbd98->emul.scancode = scancode;
@@ -187,27 +187,31 @@
 			}
 
 			input_sync(&kbd98->dev);
-			return;
+			break;
 
 		case KEY_CAPSLOCK:
 			input_report_key(&kbd98->dev, keycode, 1);
 			input_sync(&kbd98->dev);
 			input_report_key(&kbd98->dev, keycode, 0);
 			input_sync(&kbd98->dev);
-			return;
+			break;
 
 		case KBD98_KEY_NULL:
-			return;
+			break;
 
 		case 0:
 			printk(KERN_WARNING "kbd98.c: Unknown key (scancode %#x) %s.\n",
 				data & KBD98_KEY, data & KBD98_RELEASE ? "released" : "pressed");
-			return;
+			break;
 
 		default:
 			input_report_key(&kbd98->dev, keycode, press);
 			input_sync(&kbd98->dev);
-		}
+			break;
+	}
+
+out:
+	return IRQ_HANDLED;
 }
 
 /*
@@ -243,7 +247,7 @@
 	int i;
 
 	kbd98->cmdcnt = receive;
-	
+
 	if (command & 0xff)
 		if (kbd98_sendbyte(kbd98, command & 0xff))
 			return (kbd98->cmdcnt = 0) - 1;
@@ -258,7 +262,7 @@
 		for (i = 0; i < receive; i++)
 			param[i] = kbd98->cmdbuf[(receive - 1) - i];
 
-	if (kbd98->cmdcnt) 
+	if (kbd98->cmdcnt)
 		return (kbd98->cmdcnt = 0) - 1;
 
 	return 0;
@@ -318,7 +322,7 @@
 
 	memset(kbd98, 0, sizeof(struct kbd98));
 	kbd98->emul.scancode = KBD98_KEY_UNKNOWN;
-	
+
 	kbd98->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
 	kbd98->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_KANA);
 
--- diff/drivers/input/keyboard/Kconfig	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/keyboard/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -62,7 +62,7 @@
 	  Say Y here if you want to use the old IBM PC/XT keyboard (or
 	  compatible) on your system. This is only possible with a
 	  parallel port keyboard adapter, you cannot connect it to the
-	  keyboard port on a PC that runs Linux. 
+	  keyboard port on a PC that runs Linux.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called xtkbd.
@@ -92,19 +92,7 @@
 	depends on AMIGA && INPUT && INPUT_KEYBOARD
 	help
 	  Say Y here if you are running Linux on any AMIGA and have a keyboard
-	  attached.	
+	  attached.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called amikbd.
-
-config KEYBOARD_98KBD
-	tristate "NEC PC-9800 Keyboard support"
-	depends on X86_PC9800 && INPUT && INPUT_KEYBOARD
-	select SERIO
-	help
-	  Say Y here if you want to use the NEC PC-9801/PC-9821 keyboard (or
-	  compatible) on your system. 
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called 98kbd.
-
--- diff/drivers/input/keyboard/atkbd.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/keyboard/atkbd.c	2004-05-27 18:34:16.000000000 +0100
@@ -26,7 +26,6 @@
 #include <linux/input.h>
 #include <linux/serio.h>
 #include <linux/workqueue.h>
-#include <linux/timer.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
@@ -81,13 +80,13 @@
 	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
 
 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
-	173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
+	217,100,255,  0, 97,165,172,  0,156,  0,  0,  0,  0,  0,187,125,
+	173,114,  0,113,  0,  0,189,126,128,  0,  0,140,  0,  0,  0,127,
 	159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
 	157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
 	226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
 	  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
-	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
+	110,111,108,112,106,103,171,119,  0,118,109,  0, 99,104,119,  0,
 
 	  0,  0,  0, 65, 99,
 };
@@ -173,22 +172,24 @@
 	unsigned char keycode[512];
 	struct input_dev dev;
 	struct serio *serio;
-	struct timer_list timer;
+
 	char name[64];
 	char phys[32];
+	unsigned short id;
+	unsigned char set;
+	unsigned int translated:1;
+	unsigned int extra:1;
+	unsigned int write:1;
+
 	unsigned char cmdbuf[4];
 	unsigned char cmdcnt;
-	unsigned char set;
-	unsigned char extra;
-	unsigned char release;
-	int lastkey;
 	volatile signed char ack;
 	unsigned char emul;
-	unsigned short id;
-	unsigned char write;
-	unsigned char translated;
-	unsigned char resend;
-	unsigned char bat_xl;
+	unsigned int resend:1;
+	unsigned int release:1;
+	unsigned int bat_xl:1;
+	unsigned int enabled:1;
+
 	unsigned int last;
 	unsigned long time;
 };
@@ -243,11 +244,14 @@
 				goto out;
 		}
 
-	if (atkbd->cmdcnt) {
+	if (atkbd->cmdcnt && atkbd->ack == 1) {
 		atkbd->cmdbuf[--atkbd->cmdcnt] = code;
 		goto out;
 	}
 
+	if (!atkbd->enabled)
+		goto out;
+
 	if (atkbd->translated) {
 
 		if (atkbd->emul ||
@@ -300,15 +304,20 @@
 		case ATKBD_KEY_NULL:
 			break;
 		case ATKBD_KEY_UNKNOWN:
-			printk(KERN_WARNING "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
-				atkbd->release ? "released" : "pressed",
-				atkbd->translated ? "translated" : "raw",
-				atkbd->set, code, serio->phys);
-			if (atkbd->translated && atkbd->set == 2 && code == 0x7a)
-				printk(KERN_WARNING "atkbd.c: This is an XFree86 bug. It shouldn't access"
-					" hardware directly.\n");
-			else
-				printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",						code & 0x80 ? "e0" : "", code & 0x7f);
+			if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) {
+				printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, "
+				       "like XFree86, might be trying access hardware directly.\n",
+				       data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
+			} else {
+				printk(KERN_WARNING "atkbd.c: Unknown key %s "
+				       "(%s set %d, code %#x on %s).\n",
+				       atkbd->release ? "released" : "pressed",
+				       atkbd->translated ? "translated" : "raw",
+				       atkbd->set, code, serio->phys);
+				printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' "
+				       "to make it known.\n",
+				       code & 0x80 ? "e0" : "", code & 0x7f);
+			}
 			break;
 		case ATKBD_SCR_1:
 			scroll = 1 - atkbd->release * 2;
@@ -365,10 +374,12 @@
  * replacement anyway, and they only make a mess in the protocol.
  */
 
-static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
+static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte, int cmdcnt)
 {
 	int timeout = 20000; /* 200 msec */
 	atkbd->ack = 0;
+	wmb(); /* First clear ACK, then write how many reply bytes we want... though maybe it would want real spinlock */
+	atkbd->cmdcnt = cmdcnt;
 
 #ifdef ATKBD_DEBUG
 	printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
@@ -393,8 +404,6 @@
 	int receive = (command >> 8) & 0xf;
 	int i;
 
-	atkbd->cmdcnt = receive;
-
 	if (command == ATKBD_CMD_RESET_BAT)
 		timeout = 2000000; /* 2 sec */
 
@@ -403,11 +412,11 @@
 			atkbd->cmdbuf[(receive - 1) - i] = param[i];
 
 	if (command & 0xff)
-		if (atkbd_sendbyte(atkbd, command & 0xff))
+		if (atkbd_sendbyte(atkbd, command & 0xff, send ? 0 : receive))
 			return (atkbd->cmdcnt = 0) - 1;
 
 	for (i = 0; i < send; i++)
-		if (atkbd_sendbyte(atkbd, param[i]))
+		if (atkbd_sendbyte(atkbd, param[i], (i != send - 1) ? 0 : receive))
 			return (atkbd->cmdcnt = 0) - 1;
 
 	while (atkbd->cmdcnt && timeout--) {
@@ -745,6 +754,8 @@
 		atkbd->id = 0xab00;
 	}
 
+	atkbd->enabled = 1;
+
 	if (atkbd->extra) {
 		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
 		sprintf(atkbd->name, "AT Set 2 Extra keyboard");
@@ -809,12 +820,12 @@
 		param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
 		         | (test_bit(LED_NUML,    atkbd->dev.led) ? 2 : 0)
  		         | (test_bit(LED_CAPSL,   atkbd->dev.led) ? 4 : 0);
-		
+
 		if (atkbd_probe(atkbd))
 			return -1;
 		if (atkbd->set != atkbd_set_3(atkbd))
 			return -1;
-		
+
 		atkbd_enable(atkbd);
 
 		if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
--- diff/drivers/input/keyboard/maple_keyb.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/keyboard/maple_keyb.c	2004-05-27 18:34:16.000000000 +0100
@@ -139,7 +139,7 @@
 
 	kbd->dev.name = dev->product_name;
 	kbd->dev.id.bustype = BUS_MAPLE;
-	
+
 	input_register_device(&kbd->dev);
 
 	maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD);
--- diff/drivers/input/keyboard/sunkbd.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/keyboard/sunkbd.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -148,7 +148,7 @@
 		case EV_LED:
 
 			sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
-			sunkbd->serio->write(sunkbd->serio, 
+			sunkbd->serio->write(sunkbd->serio,
 				(!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) |
 				(!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led));
 			return 0;
@@ -160,7 +160,7 @@
 				case SND_CLICK:
 					sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
 					return 0;
-	
+
 				case SND_BELL:
 					sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
 					return 0;
@@ -210,7 +210,7 @@
 	wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
 
 	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
-	sunkbd->serio->write(sunkbd->serio, 
+	sunkbd->serio->write(sunkbd->serio,
 		(!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) |
 		(!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led));
 	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd));
@@ -231,7 +231,7 @@
 
 	if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD)
 		return;
-	
+
 	if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL)))
 		return;
 
--- diff/drivers/input/keyboard/xtkbd.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/keyboard/xtkbd.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -43,7 +43,7 @@
 #define XTKBD_KEY	0x7f
 #define XTKBD_RELEASE	0x80
 
-static unsigned char xtkbd_keycode[256] = {	 
+static unsigned char xtkbd_keycode[256] = {
 	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
@@ -98,7 +98,7 @@
 		return;
 
 	memset(xtkbd, 0, sizeof(struct xtkbd));
-	
+
 	xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 
 	xtkbd->serio = serio;
--- diff/drivers/input/misc/98spkr.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/input/misc/98spkr.c	2004-05-27 18:34:16.000000000 +0100
@@ -42,11 +42,11 @@
 		case SND_BELL: if (value) value = 1000;
 		case SND_TONE: break;
 		default: return -1;
-	} 
+	}
 
 	if (value > 20 && value < 32767)
 		count = PIT_TICK_RATE / value;
-	
+
 	spin_lock_irqsave(&i8253_beep_lock, flags);
 
 	if (count) {
--- diff/drivers/input/misc/Kconfig	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/input/misc/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -40,10 +40,6 @@
 	tristate "M68k Beeper support"
 	depends on M68K && INPUT && INPUT_MISC
 
-config INPUT_98SPKR
-	tristate "PC-9800 Speaker support"
-	depends on X86_PC9800 && INPUT && INPUT_MISC
-
 config INPUT_UINPUT
 	tristate "User level driver support"
 	depends on INPUT && INPUT_MISC
--- diff/drivers/input/misc/pcspkr.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/input/misc/pcspkr.c	2004-05-27 18:34:16.000000000 +0100
@@ -41,11 +41,11 @@
 		case SND_BELL: if (value) value = 1000;
 		case SND_TONE: break;
 		default: return -1;
-	} 
+	}
 
 	if (value > 20 && value < 32767)
 		count = PIT_TICK_RATE / value;
-	
+
 	spin_lock_irqsave(&i8253_beep_lock, flags);
 
 	if (count) {
--- diff/drivers/input/misc/sparcspkr.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/misc/sparcspkr.c	2004-05-27 18:34:16.000000000 +0100
@@ -53,11 +53,11 @@
 		case SND_BELL: if (value) value = 1000;
 		case SND_TONE: break;
 		default: return -1;
-	} 
+	}
 
 	if (value > 20 && value < 32767)
 		count = 1193182 / value;
-	
+
 	spin_lock_irqsave(&beep_lock, flags);
 
 	/* EBUS speaker only has on/off state, the frequency does not
@@ -108,11 +108,11 @@
 		case SND_BELL: if (value) value = 1000;
 		case SND_TONE: break;
 		default: return -1;
-	} 
+	}
 
 	if (value > 20 && value < 32767)
 		count = 1193182 / value;
-	
+
 	spin_lock_irqsave(&beep_lock, flags);
 
 	if (count) {
--- diff/drivers/input/misc/uinput.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/misc/uinput.c	2004-05-27 18:34:16.000000000 +0100
@@ -18,7 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
- * 
+ *
  * Changes/Revisions:
  *	0.1	20/06/2002
  *		- first public version
@@ -68,7 +68,7 @@
 static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
 {
 	return 0;
-}					
+}
 
 static int uinput_create_device(struct uinput_device *udev)
 {
@@ -123,7 +123,7 @@
 	memset(newinput, 0, sizeof(struct input_dev));
 
 	newdev->dev = newinput;
-	
+
 	file->private_data = newdev;
 
 	return 0;
@@ -137,16 +137,16 @@
 {
 	unsigned int cnt;
 	int retval = 0;
-	
+
 	for (cnt = 0; cnt < ABS_MAX; cnt++) {
-		if (!test_bit(cnt, dev->absbit)) 
+		if (!test_bit(cnt, dev->absbit))
 			continue;
-		
+
 		if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
 		    (dev->absmax[cnt] <= dev->absmin[cnt])) {
-			printk(KERN_DEBUG 
+			printk(KERN_DEBUG
 				"%s: invalid abs[%02x] min:%d max:%d\n",
-				UINPUT_NAME, cnt, 
+				UINPUT_NAME, cnt,
 				dev->absmin[cnt], dev->absmax[cnt]);
 			retval = -EINVAL;
 			break;
@@ -154,7 +154,7 @@
 
 		if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
 		    (dev->absflat[cnt] > dev->absmax[cnt])) {
-			printk(KERN_DEBUG 
+			printk(KERN_DEBUG
 				"%s: absflat[%02x] out of range: %d "
 				"(min:%d/max:%d)\n",
 				UINPUT_NAME, cnt, dev->absflat[cnt],
@@ -190,7 +190,7 @@
 		goto exit;
 	}
 
-	if (NULL != dev->name) 
+	if (NULL != dev->name)
 		kfree(dev->name);
 
 	size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
@@ -229,7 +229,7 @@
 static ssize_t uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct uinput_device	*udev = file->private_data;
-	
+
 	if (test_bit(UIST_CREATED, &(udev->state))) {
 		struct input_event	ev;
 
@@ -247,7 +247,7 @@
 {
 	struct uinput_device *udev = file->private_data;
 	int retval = 0;
-	
+
 	if (!test_bit(UIST_CREATED, &(udev->state)))
 		return -ENODEV;
 
@@ -255,16 +255,16 @@
 		return -EAGAIN;
 
 	retval = wait_event_interruptible(udev->waitq,
-			(udev->head != udev->tail) || 
+			(udev->head != udev->tail) ||
 			!test_bit(UIST_CREATED, &(udev->state)));
-	
+
 	if (retval)
 		return retval;
 
 	if (!test_bit(UIST_CREATED, &(udev->state)))
 		return -ENODEV;
 
-	while ((udev->head != udev->tail) && 
+	while ((udev->head != udev->tail) &&
 	    (retval + sizeof(struct input_event) <= count)) {
 		if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
 		    sizeof(struct input_event))) return -EFAULT;
@@ -284,7 +284,7 @@
 	if (udev->head != udev->tail)
 		return POLLIN | POLLRDNORM;
 
-	return 0;			
+	return 0;
 }
 
 static int uinput_burn_device(struct uinput_device *udev)
@@ -318,7 +318,7 @@
 		case UI_DEV_CREATE:
 			retval = uinput_create_device(udev);
 			break;
-			
+
 		case UI_DEV_DESTROY:
 			retval = uinput_destroy_device(udev);
 			break;
@@ -330,7 +330,7 @@
 			}
 			set_bit(arg, udev->dev->evbit);
 			break;
-			
+
 		case UI_SET_KEYBIT:
 			if (arg > KEY_MAX) {
 				retval = -EINVAL;
@@ -338,7 +338,7 @@
 			}
 			set_bit(arg, udev->dev->keybit);
 			break;
-			
+
 		case UI_SET_RELBIT:
 			if (arg > REL_MAX) {
 				retval = -EINVAL;
@@ -346,7 +346,7 @@
 			}
 			set_bit(arg, udev->dev->relbit);
 			break;
-			
+
 		case UI_SET_ABSBIT:
 			if (arg > ABS_MAX) {
 				retval = -EINVAL;
@@ -354,7 +354,7 @@
 			}
 			set_bit(arg, udev->dev->absbit);
 			break;
-			
+
 		case UI_SET_MSCBIT:
 			if (arg > MSC_MAX) {
 				retval = -EINVAL;
@@ -362,7 +362,7 @@
 			}
 			set_bit(arg, udev->dev->mscbit);
 			break;
-			
+
 		case UI_SET_LEDBIT:
 			if (arg > LED_MAX) {
 				retval = -EINVAL;
@@ -370,7 +370,7 @@
 			}
 			set_bit(arg, udev->dev->ledbit);
 			break;
-			
+
 		case UI_SET_SNDBIT:
 			if (arg > SND_MAX) {
 				retval = -EINVAL;
@@ -378,7 +378,7 @@
 			}
 			set_bit(arg, udev->dev->sndbit);
 			break;
-			
+
 		case UI_SET_FFBIT:
 			if (arg > FF_MAX) {
 				retval = -EINVAL;
@@ -386,7 +386,7 @@
 			}
 			set_bit(arg, udev->dev->ffbit);
 			break;
-			
+
 		default:
 			retval = -EFAULT;
 	}
--- diff/drivers/input/mouse/Kconfig	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -130,14 +130,3 @@
 	  described in the source file). This driver should, in theory,
 	  also work with the digitizer DEC produced, but it isn't tested
 	  with that (I don't have the hardware yet).
-
-config MOUSE_PC9800
-	tristate "NEC PC-9800 busmouse"
-	depends on X86_PC9800 && INPUT && INPUT_MOUSE && ISA
-	help
-	  Say Y here if you have NEC PC-9801/PC-9821 computer and want its
-	  native mouse supported.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called 98busmouse.
-
--- diff/drivers/input/mouse/Makefile	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/Makefile	2004-05-27 18:34:16.000000000 +0100
@@ -10,7 +10,6 @@
 obj-$(CONFIG_MOUSE_LOGIBM)	+= logibm.o
 obj-$(CONFIG_MOUSE_MAPLE)	+= maplemouse.o
 obj-$(CONFIG_MOUSE_PC110PAD)	+= pc110pad.o
-obj-$(CONFIG_MOUSE_PC9800)	+= 98busmouse.o
 obj-$(CONFIG_MOUSE_PS2)		+= psmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
--- diff/drivers/input/mouse/logips2pp.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/logips2pp.c	2004-05-27 18:34:16.000000000 +0100
@@ -14,6 +14,25 @@
 #include "psmouse.h"
 #include "logips2pp.h"
 
+/* Logitech mouse types */
+#define PS2PP_KIND_WHEEL	1
+#define PS2PP_KIND_MX		2
+#define PS2PP_KIND_TP3		3
+
+/* Logitech mouse features */
+#define PS2PP_WHEEL		0x01
+#define PS2PP_HWHEEL		0x02
+#define PS2PP_SIDE_BTN		0x04
+#define PS2PP_EXTRA_BTN		0x08
+#define PS2PP_TASK_BTN		0x10
+#define PS2PP_NAV_BTN		0x20
+
+struct ps2pp_info {
+	const int model;
+	unsigned const int kind;
+	unsigned const int features;
+};
+
 /*
  * Process a PS2++ or PS2T++ packet.
  */
@@ -63,7 +82,6 @@
 		packet[0] &= 0x0f;
 		packet[1] = 0;
 		packet[2] = 0;
-
 	}
 }
 
@@ -76,18 +94,9 @@
 
 static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
 {
-	unsigned char d;
-	int i;
-
-	if (psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11))
+	if (psmouse_sliced_command(psmouse, command))
 		return -1;
 
-	for (i = 6; i >= 0; i -= 2) {
-		d = (command >> i) & 3;
-		if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
-			return -1;
-	}
-
 	if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
 		return -1;
 
@@ -99,7 +108,7 @@
  * enabled if we do nothing to it. Of course I put this in because I want it
  * disabled :P
  * 1 - enabled (if previously disabled, also default)
- * 0/2 - disabled 
+ * 0/2 - disabled
  */
 
 static void ps2pp_set_smartscroll(struct psmouse *psmouse)
@@ -113,14 +122,11 @@
 	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
 	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
 
-	if (psmouse_smartscroll == 1) 
-		param[0] = 1;
-	else
-	if (psmouse_smartscroll > 2)
-		return;
-
-	/* else leave param[0] == 0 to disable */
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	if (psmouse_smartscroll < 2) {
+		/* 0 - disabled, 1 - enabled */
+		param[0] = psmouse_smartscroll;
+		psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	}
 }
 
 /*
@@ -138,133 +144,167 @@
 	psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES);
 }
 
+static struct ps2pp_info *get_model_info(unsigned char model)
+{
+	static struct ps2pp_info ps2pp_list[] = {
+		{ 12,	0,			PS2PP_SIDE_BTN},
+		{ 13,	0,			0 },
+		{ 40,	0,			PS2PP_SIDE_BTN },
+		{ 41,	0,			PS2PP_SIDE_BTN },
+		{ 42,	0,			PS2PP_SIDE_BTN },
+		{ 43,	0,			PS2PP_SIDE_BTN },
+		{ 50,	0,			0 },
+		{ 51,	0,			0 },
+		{ 52,	PS2PP_KIND_WHEEL,	PS2PP_SIDE_BTN | PS2PP_WHEEL },
+		{ 53,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
+		{ 61,	PS2PP_KIND_MX,
+				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX700 */
+		{ 73,	0,			PS2PP_SIDE_BTN },
+		{ 75,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
+		{ 76,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
+		{ 80,	PS2PP_KIND_WHEEL,	PS2PP_SIDE_BTN | PS2PP_WHEEL },
+		{ 81,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
+		{ 83,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
+		{ 88,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
+		{ 96,	0,			0 },
+		{ 97,	PS2PP_KIND_TP3,		PS2PP_WHEEL | PS2PP_HWHEEL },
+		{ 100,	PS2PP_KIND_MX,
+				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX510 */
+		{ 112,	PS2PP_KIND_MX,
+				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX500 */
+		{ 114,	PS2PP_KIND_MX,
+				PS2PP_WHEEL | PS2PP_SIDE_BTN |
+				PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },	/* M310 */
+		{ }
+	};
+	int i;
+
+	for (i = 0; ps2pp_list[i].model; i++)
+		if (model == ps2pp_list[i].model)
+			return &ps2pp_list[i];
+	return NULL;
+}
+
 /*
- * Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or
- * touchpad.
+ * Set up input device's properties based on the detected mouse model.
  */
 
-static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
+static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info)
 {
-	int i;
-	static struct _logips2_list {
-		const int model;
-		unsigned const int features;
-	} logips2pp_list [] = {
-		{ 12,	PS2PP_4BTN},
-		{ 13,	0 },
-		{ 40,	PS2PP_4BTN },
-		{ 41,	PS2PP_4BTN },
-		{ 42,	PS2PP_4BTN },
-		{ 43,	PS2PP_4BTN },
-		{ 50,	0 },
-		{ 51,	0 },
-		{ 52,	PS2PP_4BTN | PS2PP_WHEEL },
-		{ 53,	PS2PP_WHEEL },
-		{ 61,	PS2PP_WHEEL | PS2PP_MX },	/* MX700 */
-		{ 73,	PS2PP_4BTN },
-		{ 75,	PS2PP_WHEEL },
-		{ 76,	PS2PP_WHEEL },
-		{ 80,	PS2PP_4BTN | PS2PP_WHEEL },
-		{ 81,	PS2PP_WHEEL },
-		{ 83,	PS2PP_WHEEL },
-		{ 88,	PS2PP_WHEEL },
-		{ 96,	0 },
-		{ 97,	0 },
-		{ 100 ,	PS2PP_WHEEL | PS2PP_MX },	/* MX510 */
-		{ 112 ,	PS2PP_WHEEL | PS2PP_MX },	/* MX500 */
-		{ 114 ,	PS2PP_WHEEL | PS2PP_MX | PS2PP_MX310 },	/* MX310 */
-		{ }
-	};
+	if (model_info->features & PS2PP_SIDE_BTN)
+		set_bit(BTN_SIDE, psmouse->dev.keybit);
 
-	psmouse->vendor = "Logitech";
-	psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
+	if (model_info->features & PS2PP_EXTRA_BTN)
+		set_bit(BTN_EXTRA, psmouse->dev.keybit);
 
-	if (param[1] < 3)
-		clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
-	if (param[1] < 2)
-		clear_bit(BTN_RIGHT, psmouse->dev.keybit);
-
-	psmouse->type = PSMOUSE_PS2;
-
-	for (i = 0; logips2pp_list[i].model; i++){
-		if (logips2pp_list[i].model == psmouse->model){
-			psmouse->type = PSMOUSE_PS2PP;
-			if (logips2pp_list[i].features & PS2PP_4BTN)
-				set_bit(BTN_SIDE, psmouse->dev.keybit);
-
-			if (logips2pp_list[i].features & PS2PP_WHEEL){
-				set_bit(REL_WHEEL, psmouse->dev.relbit);
-				psmouse->name = "Wheel Mouse";
-			}
-			if (logips2pp_list[i].features & PS2PP_MX) {
-				set_bit(BTN_SIDE, psmouse->dev.keybit);
-				set_bit(BTN_EXTRA, psmouse->dev.keybit);
-				set_bit(BTN_TASK, psmouse->dev.keybit);
-				if (!(logips2pp_list[i].features & PS2PP_MX310)){
-					set_bit(BTN_BACK, psmouse->dev.keybit);
-					set_bit(BTN_FORWARD, psmouse->dev.keybit);
-				}
-				psmouse->name = "MX Mouse";
-			}
+	if (model_info->features & PS2PP_TASK_BTN)
+		set_bit(BTN_TASK, psmouse->dev.keybit);
+
+	if (model_info->features & PS2PP_NAV_BTN) {
+		set_bit(BTN_FORWARD, psmouse->dev.keybit);
+		set_bit(BTN_BACK, psmouse->dev.keybit);
+	}
+
+	if (model_info->features & PS2PP_WHEEL)
+		set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+	if (model_info->features & PS2PP_HWHEEL)
+		set_bit(REL_HWHEEL, psmouse->dev.relbit);
+
+	switch (model_info->kind) {
+		case PS2PP_KIND_WHEEL:
+			psmouse->name = "Wheel Mouse";
+			break;
+
+		case PS2PP_KIND_MX:
+			psmouse->name = "MX Mouse";
+			break;
+
+		case PS2PP_KIND_TP3:
+			psmouse->name = "TouchPad 3";
 			break;
-		}
 	}
+}
+
+
 /*
- * Do Logitech PS2++ / PS2T++ magic init.
+ * Logitech magic init. Detect whether the mouse is a Logitech one
+ * and its exact model and try turning on extended protocol for ones
+ * that support it.
  */
-	if (psmouse->type == PSMOUSE_PS2PP) {
 
-		if (psmouse->model == 97) { /* TouchPad 3 */
+int ps2pp_init(struct psmouse *psmouse, int set_properties)
+{
+	unsigned char param[4];
+	unsigned char protocol = PSMOUSE_PS2;
+	unsigned char model, buttons;
+	struct ps2pp_info *model_info;
 
-			set_bit(REL_WHEEL, psmouse->dev.relbit);
-			set_bit(REL_HWHEEL, psmouse->dev.relbit);
+	param[0] = 0;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	param[1] = 0;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+
+	if (param[1] != 0) {
+		model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
+		buttons = param[1];
+		model_info = get_model_info(model);
+
+/*
+ * Do Logitech PS2++ / PS2T++ magic init.
+ */
+		if (model == 97) { /* Touch Pad 3 */
 
-			param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */
+			/* Unprotect RAM */
+			param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
 			psmouse_command(psmouse, param, 0x30d1);
-			param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */
+			/* Enable features */
+			param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
 			psmouse_command(psmouse, param, 0x30d1);
-			param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */
+			/* Enable PS2++ */
+			param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
 			psmouse_command(psmouse, param, 0x30d1);
 
 			param[0] = 0;
 			if (!psmouse_command(psmouse, param, 0x13d1) &&
-				param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
-				psmouse->name = "TouchPad 3";
-				return PSMOUSE_PS2TPP;
+			    param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
+				protocol = PSMOUSE_PS2TPP;
 			}
 
-		} else {
+		} else if (get_model_info(model) != NULL) {
 
 			param[0] = param[1] = param[2] = 0;
 			ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
 			ps2pp_cmd(psmouse, param, 0xDB);
 
-			if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 &&
-				(param[2] & 3) == ((param[1] >> 2) & 3)) {
-					ps2pp_set_smartscroll(psmouse);
-					return PSMOUSE_PS2PP;
+			if ((param[0] & 0x78) == 0x48 &&
+			    (param[1] & 0xf3) == 0xc2 &&
+			    (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
+				ps2pp_set_smartscroll(psmouse);
+				protocol = PSMOUSE_PS2PP;
 			}
 		}
-	}
 
-	return 0;
-}
-
-/*
- * Logitech magic init.
- */
-int ps2pp_detect(struct psmouse *psmouse)
-{
-	unsigned char param[4];
+		if (set_properties) {
+			psmouse->vendor = "Logitech";
+			psmouse->model = model;
+
+			if (buttons < 3)
+				clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
+			if (buttons < 2)
+				clear_bit(BTN_RIGHT, psmouse->dev.keybit);
 
-	param[0] = 0;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	param[1] = 0;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+			if (model_info)
+				ps2pp_set_model_properties(psmouse, model_info);
+		}
+	}
 
-	return param[1] != 0 ? ps2pp_detect_model(psmouse, param) : 0;
+	return protocol;
 }
 
--- diff/drivers/input/mouse/logips2pp.h	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/logips2pp.h	2004-05-27 18:34:16.000000000 +0100
@@ -11,13 +11,8 @@
 #ifndef _LOGIPS2PP_H
 #define _LOGIPS2PP_H
 
-#define PS2PP_4BTN	0x01
-#define PS2PP_WHEEL	0x02
-#define PS2PP_MX	0x04
-#define PS2PP_MX310	0x08
-
-struct psmouse;
 void ps2pp_process_packet(struct psmouse *psmouse);
 void ps2pp_set_800dpi(struct psmouse *psmouse);
-int ps2pp_detect(struct psmouse *psmouse);
+int ps2pp_init(struct psmouse *psmouse, int set_properties);
+
 #endif
--- diff/drivers/input/mouse/psmouse-base.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/psmouse-base.c	2004-05-27 18:34:16.000000000 +0100
@@ -43,9 +43,9 @@
 module_param_named(smartscroll, psmouse_smartscroll, bool, 0);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
-unsigned int psmouse_resetafter;
+static unsigned int psmouse_resetafter;
 module_param_named(resetafter, psmouse_resetafter, uint, 0);
-MODULE_PARM_DESC(resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
+MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
 __obsolete_setup("psmouse_noext");
 __obsolete_setup("psmouse_resolution=");
@@ -56,15 +56,22 @@
 static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
 
 /*
- * psmouse_process_packet() analyzes the PS/2 mouse packet contents and
- * reports relevant events to the input module.
+ * psmouse_process_byte() analyzes the PS/2 data stream and reports
+ * relevant events to the input module once full packet has arrived.
  */
 
-static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
 {
 	struct input_dev *dev = &psmouse->dev;
 	unsigned char *packet = psmouse->packet;
 
+	if (psmouse->pktcnt < 3 + (psmouse->type >= PSMOUSE_GENPS))
+		return PSMOUSE_GOOD_DATA;
+
+/*
+ * Full packet accumulated, process it
+ */
+
 	input_regs(dev, regs);
 
 /*
@@ -112,6 +119,8 @@
 	input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
 
 	input_sync(dev);
+
+	return PSMOUSE_FULL_PACKET;
 }
 
 /*
@@ -123,6 +132,7 @@
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
 	struct psmouse *psmouse = serio->private;
+	psmouse_ret_t rc;
 
 	if (psmouse->state == PSMOUSE_IGNORE)
 		goto out;
@@ -180,7 +190,7 @@
 		if (psmouse->pktcnt == 2) {
 			if (psmouse->packet[1] == PSMOUSE_RET_ID) {
 				psmouse->state = PSMOUSE_IGNORE;
-				serio_rescan(serio);
+				serio_reconnect(serio);
 				goto out;
 			}
 			if (psmouse->type == PSMOUSE_SYNAPTICS) {
@@ -193,19 +203,32 @@
 		}
 	}
 
-	if (psmouse->type == PSMOUSE_SYNAPTICS) {
-		/*
-		 * The synaptics driver has its own resync logic,
-		 * so it needs to receive all bytes one at a time.
-		 */
-		synaptics_process_byte(psmouse, regs);
-		goto out;
-	}
+	rc = psmouse->protocol_handler(psmouse, regs);
 
-	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
-		psmouse_process_packet(psmouse, regs);
-		psmouse->pktcnt = 0;
-		goto out;
+	switch (rc) {
+		case PSMOUSE_BAD_DATA:
+			printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
+				psmouse->name, psmouse->phys, psmouse->pktcnt);
+			psmouse->pktcnt = 0;
+
+			if (++psmouse->out_of_sync == psmouse_resetafter) {
+				psmouse->state = PSMOUSE_IGNORE;
+				printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
+				serio_reconnect(psmouse->serio);
+			}
+			break;
+
+		case PSMOUSE_FULL_PACKET:
+			psmouse->pktcnt = 0;
+			if (psmouse->out_of_sync) {
+				psmouse->out_of_sync = 0;
+				printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
+					psmouse->name, psmouse->phys);
+			}
+			break;
+
+		case PSMOUSE_GOOD_DATA:
+			break;
 	}
 out:
 	return IRQ_HANDLED;
@@ -289,6 +312,30 @@
 
 
 /*
+ * psmouse_sliced_command() sends an extended PS/2 command to the mouse
+ * using sliced syntax, understood by advanced devices, such as Logitech
+ * or Synaptics touchpads. The command is encoded as:
+ * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
+ * is the command.
+ */
+int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
+{
+	int i;
+
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+		return -1;
+
+	for (i = 6; i >= 0; i -= 2) {
+		unsigned char d = (command >> i) & 3;
+		if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+/*
  * psmouse_reset() resets the mouse into power-on state.
  */
 int psmouse_reset(struct psmouse *psmouse)
@@ -363,31 +410,31 @@
  * the mouse may have.
  */
 
-static int psmouse_extensions(struct psmouse *psmouse)
+static int psmouse_extensions(struct psmouse *psmouse,
+			      unsigned int max_proto, int set_properties)
 {
 	int synaptics_hardware = 0;
 
-	psmouse->vendor = "Generic";
-	psmouse->name = "Mouse";
-	psmouse->model = 0;
-
 /*
  * Try Synaptics TouchPad
  */
-	if (psmouse_max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
+	if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
 		synaptics_hardware = 1;
-		psmouse->vendor = "Synaptics";
-		psmouse->name = "TouchPad";
 
-		if (psmouse_max_proto > PSMOUSE_IMEX) {
-			if (synaptics_init(psmouse) == 0)
+		if (set_properties) {
+			psmouse->vendor = "Synaptics";
+			psmouse->name = "TouchPad";
+		}
+
+		if (max_proto > PSMOUSE_IMEX) {
+			if (!set_properties || synaptics_init(psmouse) == 0)
 				return PSMOUSE_SYNAPTICS;
 /*
  * Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
  * Unfortunately Logitech/Genius probes confuse some firmware versions so
  * we'll have to skip them.
  */
-			psmouse_max_proto = PSMOUSE_IMEX;
+			max_proto = PSMOUSE_IMEX;
 		}
 /*
  * Make sure that touchpad is in relative mode, gestures (taps) are enabled
@@ -395,35 +442,46 @@
 		synaptics_reset(psmouse);
 	}
 
-	if (psmouse_max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
-		set_bit(BTN_EXTRA, psmouse->dev.keybit);
-		set_bit(BTN_SIDE, psmouse->dev.keybit);
-		set_bit(REL_WHEEL, psmouse->dev.relbit);
+	if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
+
+		if (set_properties) {
+			set_bit(BTN_EXTRA, psmouse->dev.keybit);
+			set_bit(BTN_SIDE, psmouse->dev.keybit);
+			set_bit(REL_WHEEL, psmouse->dev.relbit);
+			psmouse->vendor = "Genius";
+			psmouse->name = "Wheel Mouse";
+		}
 
-		psmouse->vendor = "Genius";
-		psmouse->name = "Wheel Mouse";
 		return PSMOUSE_GENPS;
 	}
 
-	if (psmouse_max_proto > PSMOUSE_IMEX) {
-		int type = ps2pp_detect(psmouse);
-		if (type)
+	if (max_proto > PSMOUSE_IMEX) {
+		int type = ps2pp_init(psmouse, set_properties);
+		if (type > PSMOUSE_PS2)
 			return type;
 	}
 
-	if (psmouse_max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) {
-		set_bit(REL_WHEEL, psmouse->dev.relbit);
+	if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse)) {
 
-		if (psmouse_max_proto >= PSMOUSE_IMEX &&
-					im_explorer_detect(psmouse)) {
+		if (set_properties) {
+			set_bit(REL_WHEEL, psmouse->dev.relbit);
 			set_bit(BTN_SIDE, psmouse->dev.keybit);
 			set_bit(BTN_EXTRA, psmouse->dev.keybit);
+			if (!psmouse->name)
+				psmouse->name = "Explorer Mouse";
+		}
+
+		return PSMOUSE_IMEX;
+	}
+
+	if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) {
 
-			psmouse->name = "Explorer Mouse";
-			return PSMOUSE_IMEX;
+		if (set_properties) {
+			set_bit(REL_WHEEL, psmouse->dev.relbit);
+			if (!psmouse->name)
+				psmouse->name = "Wheel Mouse";
 		}
 
-		psmouse->name = "Wheel Mouse";
 		return PSMOUSE_IMPS;
 	}
 
@@ -473,12 +531,7 @@
 	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
 		printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys);
 
-/*
- * And here we try to determine if it has any extensions over the
- * basic PS/2 3-button mouse.
- */
-
-	return psmouse->type = psmouse_extensions(psmouse);
+	return 0;
 }
 
 /*
@@ -616,7 +669,6 @@
 	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
-
 	psmouse->state = PSMOUSE_CMD_MODE;
 	psmouse->serio = serio;
 	psmouse->dev.private = psmouse;
@@ -628,13 +680,21 @@
 		return;
 	}
 
-	if (psmouse_probe(psmouse) <= 0) {
+	if (psmouse_probe(psmouse) < 0) {
 		serio_close(serio);
 		kfree(psmouse);
 		serio->private = NULL;
 		return;
 	}
 
+	psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+	if (!psmouse->vendor)
+		psmouse->vendor = "Generic";
+	if (!psmouse->name)
+		psmouse->name = "Mouse";
+	if (!psmouse->protocol_handler)
+		psmouse->protocol_handler = psmouse_process_byte;
+
 	sprintf(psmouse->devname, "%s %s %s",
 		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
 	sprintf(psmouse->phys, "%s/input0",
@@ -668,27 +728,24 @@
 {
 	struct psmouse *psmouse = serio->private;
 	struct serio_dev *dev = serio->dev;
-	int old_type;
 
 	if (!dev || !psmouse) {
 		printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
 		return -1;
 	}
 
-	old_type = psmouse->type;
-
 	psmouse->state = PSMOUSE_CMD_MODE;
-	psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0;
+	psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0;
 	if (psmouse->reconnect) {
 	       if (psmouse->reconnect(psmouse))
 			return -1;
-	} else if (psmouse_probe(psmouse) != old_type)
+	} else if (psmouse_probe(psmouse) < 0 ||
+		   psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
 		return -1;
 
 	/* ok, the device type (and capabilities) match the old one,
 	 * we can continue using it, complete intialization
 	 */
-	psmouse->type = old_type;
 	psmouse_initialize(psmouse);
 
 	if (psmouse->ptport) {
--- diff/drivers/input/mouse/psmouse.h	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/psmouse.h	2004-05-27 18:34:16.000000000 +0100
@@ -22,6 +22,13 @@
 #define PSMOUSE_ACTIVATED	1
 #define PSMOUSE_IGNORE		2
 
+/* psmouse protocol handler return codes */
+typedef enum {
+	PSMOUSE_BAD_DATA,
+	PSMOUSE_GOOD_DATA,
+	PSMOUSE_FULL_PACKET
+} psmouse_ret_t;
+
 struct psmouse;
 
 struct psmouse_ptport {
@@ -45,6 +52,7 @@
 	unsigned char type;
 	unsigned char model;
 	unsigned long last;
+	unsigned long out_of_sync;
 	unsigned char state;
 	char acking;
 	volatile char ack;
@@ -52,6 +60,7 @@
 	char devname[64];
 	char phys[32];
 
+	psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); 
 	int (*reconnect)(struct psmouse *psmouse);
 	void (*disconnect)(struct psmouse *psmouse);
 };
@@ -65,10 +74,10 @@
 #define PSMOUSE_SYNAPTICS 	7
 
 int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
 int psmouse_reset(struct psmouse *psmouse);
 
 extern int psmouse_smartscroll;
 extern unsigned int psmouse_rate;
-extern unsigned int psmouse_resetafter;
 
 #endif /* _PSMOUSE_H */
--- diff/drivers/input/mouse/synaptics.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/synaptics.c	2004-05-27 18:34:16.000000000 +0100
@@ -44,33 +44,11 @@
  ****************************************************************************/
 
 /*
- * Use the Synaptics extended ps/2 syntax to write a special command byte.
- * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
- *                  is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd
- *                  and synaptics_mode_cmd)
- */
-static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command)
-{
-	int i;
-
-	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
-		return -1;
-
-	for (i = 6; i >= 0; i -= 2) {
-		unsigned char d = (command >> i) & 3;
-		if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
-			return -1;
-	}
-
-	return 0;
-}
-
-/*
  * Send a command to the synpatics touchpad by special commands
  */
 static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
 {
-	if (synaptics_special_cmd(psmouse, c))
+	if (psmouse_sliced_command(psmouse, c))
 		return -1;
 	if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
 		return -1;
@@ -84,7 +62,7 @@
 {
 	unsigned char param[1];
 
-	if (synaptics_special_cmd(psmouse, mode))
+	if (psmouse_sliced_command(psmouse, mode))
 		return -1;
 	param[0] = SYN_PS_SET_MODE2;
 	if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
@@ -118,17 +96,31 @@
 
 	if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
 		return -1;
-	priv->capabilities = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+	priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
 	priv->ext_cap = 0;
 	if (!SYN_CAP_VALID(priv->capabilities))
 		return -1;
 
-	if (SYN_EXT_CAP_REQUESTS(priv->capabilities)) {
+	/*
+	 * Unless capExtended is set the rest of the flags should be ignored
+	 */
+	if (!SYN_CAP_EXTENDED(priv->capabilities))
+		priv->capabilities = 0;
+
+	if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
 		if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
 			printk(KERN_ERR "Synaptics claims to have extended capabilities,"
 			       " but I'm not able to read them.");
-		} else
-			priv->ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+		} else {
+			priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
+
+			/*
+			 * if nExtBtn is greater than 8 it should be considered
+			 * invalid and treated as 0
+			 */
+			if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8)
+				priv->ext_cap &= 0xff0fff;
+		}
 	}
 	return 0;
 }
@@ -167,11 +159,12 @@
 
 	if (SYN_CAP_EXTENDED(priv->capabilities)) {
 		printk(KERN_INFO " Touchpad has extended capability bits\n");
-		if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
-		    SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) <= 8)
+		if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
 			printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
 			       (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
-		else if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
+		if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+			printk(KERN_INFO " -> middle button\n");
+		if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
 			printk(KERN_INFO " -> four buttons\n");
 		if (SYN_CAP_MULTIFINGER(priv->capabilities))
 			printk(KERN_INFO " -> multifinger detection\n");
@@ -219,21 +212,12 @@
 /*****************************************************************************
  *	Synaptics pass-through PS/2 port support
  ****************************************************************************/
-static int synaptics_pt_open(struct serio *port)
-{
-	return 0;
-}
-
-static void synaptics_pt_close(struct serio *port)
-{
-}
-
 static int synaptics_pt_write(struct serio *port, unsigned char c)
 {
 	struct psmouse *parent = port->driver;
 	char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
 
-	if (synaptics_special_cmd(parent, c))
+	if (psmouse_sliced_command(parent, c))
 		return -1;
 	if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
 		return -1;
@@ -289,166 +273,12 @@
 	port->serio.name = "Synaptics pass-through";
 	port->serio.phys = "synaptics-pt/serio0";
 	port->serio.write = synaptics_pt_write;
-	port->serio.open = synaptics_pt_open;
-	port->serio.close = synaptics_pt_close;
 	port->serio.driver = psmouse;
 
 	port->activate = synaptics_pt_activate;
 }
 
 /*****************************************************************************
- *	Driver initialization/cleanup functions
- ****************************************************************************/
-
-static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
-{
-	dev->absmin[axis] = min;
-	dev->absmax[axis] = max;
-	dev->absfuzz[axis] = fuzz;
-	dev->absflat[axis] = flat;
-
-	set_bit(axis, dev->absbit);
-}
-
-static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
-{
-	set_bit(EV_ABS, dev->evbit);
-	set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
-	set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
-	set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
-	set_bit(ABS_TOOL_WIDTH, dev->absbit);
-
-	set_bit(EV_KEY, dev->evbit);
-	set_bit(BTN_TOUCH, dev->keybit);
-	set_bit(BTN_TOOL_FINGER, dev->keybit);
-	set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
-	set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
-
-	set_bit(BTN_LEFT, dev->keybit);
-	set_bit(BTN_RIGHT, dev->keybit);
-	set_bit(BTN_FORWARD, dev->keybit);
-	set_bit(BTN_BACK, dev->keybit);
-	if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) {
-		switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
-		default:
-			/*
-			 * if nExtBtn is greater than 8 it should be considered
-			 * invalid and treated as 0
-			 */
-			break;
-		case 8:
-			set_bit(BTN_7, dev->keybit);
-			set_bit(BTN_6, dev->keybit);
-		case 6:
-			set_bit(BTN_5, dev->keybit);
-			set_bit(BTN_4, dev->keybit);
-		case 4:
-			set_bit(BTN_3, dev->keybit);
-			set_bit(BTN_2, dev->keybit);
-		case 2:
-			set_bit(BTN_1, dev->keybit);
-			set_bit(BTN_0, dev->keybit);
-			break;
-		}
-	}
-
-	clear_bit(EV_REL, dev->evbit);
-	clear_bit(REL_X, dev->relbit);
-	clear_bit(REL_Y, dev->relbit);
-}
-
-void synaptics_reset(struct psmouse *psmouse)
-{
-	/* reset touchpad back to relative mode, gestures enabled */
-	synaptics_mode_cmd(psmouse, 0);
-}
-
-static void synaptics_disconnect(struct psmouse *psmouse)
-{
-	synaptics_reset(psmouse);
-	kfree(psmouse->private);
-}
-
-static int synaptics_reconnect(struct psmouse *psmouse)
-{
-	struct synaptics_data *priv = psmouse->private;
-	struct synaptics_data old_priv = *priv;
-
-	if (!synaptics_detect(psmouse))
-		return -1;
-
-	if (synaptics_query_hardware(psmouse)) {
-		printk(KERN_ERR "Unable to query Synaptics hardware.\n");
-		return -1;
-	}
-
-	if (old_priv.identity != priv->identity ||
-	    old_priv.model_id != priv->model_id ||
-	    old_priv.capabilities != priv->capabilities ||
-    	    old_priv.ext_cap != priv->ext_cap)
-    		return -1;
-
-	if (synaptics_set_mode(psmouse, 0)) {
-		printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-int synaptics_detect(struct psmouse *psmouse)
-{
-	unsigned char param[4];
-
-	param[0] = 0;
-
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
-
-	return param[1] == 0x47;
-}
-
-int synaptics_init(struct psmouse *psmouse)
-{
-	struct synaptics_data *priv;
-
-	psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
-	if (!priv)
-		return -1;
-	memset(priv, 0, sizeof(struct synaptics_data));
-
-	if (synaptics_query_hardware(psmouse)) {
-		printk(KERN_ERR "Unable to query Synaptics hardware.\n");
-		goto init_fail;
-	}
-
-	if (synaptics_set_mode(psmouse, 0)) {
-		printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
-		goto init_fail;
-	}
-
-	priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
-
-	if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
-       		synaptics_pt_create(psmouse);
-
-	print_ident(priv);
-	set_input_params(&psmouse->dev, priv);
-
-	psmouse->disconnect = synaptics_disconnect;
-	psmouse->reconnect = synaptics_reconnect;
-
-	return 0;
-
- init_fail:
-	kfree(priv);
-	return -1;
-}
-
-/*****************************************************************************
  *	Functions to interpret the absolute mode packets
  ****************************************************************************/
 
@@ -471,17 +301,17 @@
 
 		hw->left  = (buf[0] & 0x01) ? 1 : 0;
 		hw->right = (buf[0] & 0x02) ? 1 : 0;
-		if (SYN_CAP_EXTENDED(priv->capabilities) &&
-		    (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
-			hw->up = ((buf[3] & 0x01)) ? 1 : 0;
-			if (hw->left)
-				hw->up = !hw->up;
-			hw->down = ((buf[3] & 0x02)) ? 1 : 0;
-			if (hw->right)
-				hw->down = !hw->down;
+
+		if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+			hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+
+		if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
+			hw->up   = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+			hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
 		}
+
 		if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
-		    ((buf[3] & 2) ? !hw->right : hw->right)) {
+		    ((buf[0] ^ buf[3]) & 0x02)) {
 			switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
 			default:
 				/*
@@ -490,17 +320,17 @@
 				 */
 				break;
 			case 8:
-				hw->b7 = ((buf[5] & 0x08)) ? 1 : 0;
-				hw->b6 = ((buf[4] & 0x08)) ? 1 : 0;
+				hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
+				hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
 			case 6:
-				hw->b5 = ((buf[5] & 0x04)) ? 1 : 0;
-				hw->b4 = ((buf[4] & 0x04)) ? 1 : 0;
+				hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
+				hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
 			case 4:
-				hw->b3 = ((buf[5] & 0x02)) ? 1 : 0;
-				hw->b2 = ((buf[4] & 0x02)) ? 1 : 0;
+				hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
+				hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
 			case 2:
-				hw->b1 = ((buf[5] & 0x01)) ? 1 : 0;
-				hw->b0 = ((buf[4] & 0x01)) ? 1 : 0;
+				hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
+				hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
 			}
 		}
 	} else {
@@ -525,6 +355,7 @@
 	struct synaptics_hw_state hw;
 	int num_fingers;
 	int finger_width;
+	int i;
 
 	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
 
@@ -570,32 +401,20 @@
 	input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
 	input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
 
-	input_report_key(dev, BTN_LEFT,    hw.left);
-	input_report_key(dev, BTN_RIGHT,   hw.right);
-	input_report_key(dev, BTN_FORWARD, hw.up);
-	input_report_key(dev, BTN_BACK,    hw.down);
-	if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
-		switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
-		default:
-			/*
-			 * if nExtBtn is greater than 8 it should be considered
-			 * invalid and treated as 0
-			 */
-			break;
-		case 8:
-			input_report_key(dev, BTN_7,       hw.b7);
-			input_report_key(dev, BTN_6,       hw.b6);
-		case 6:
-			input_report_key(dev, BTN_5,       hw.b5);
-			input_report_key(dev, BTN_4,       hw.b4);
-		case 4:
-			input_report_key(dev, BTN_3,       hw.b3);
-			input_report_key(dev, BTN_2,       hw.b2);
-		case 2:
-			input_report_key(dev, BTN_1,       hw.b1);
-			input_report_key(dev, BTN_0,       hw.b0);
-			break;
-		}
+	input_report_key(dev, BTN_LEFT, hw.left);
+	input_report_key(dev, BTN_RIGHT, hw.right);
+
+	if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+		input_report_key(dev, BTN_MIDDLE, hw.middle);
+
+	if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
+		input_report_key(dev, BTN_FORWARD, hw.up);
+		input_report_key(dev, BTN_BACK, hw.down);
+	}
+
+	for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
+		input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
+
 	input_sync(dev);
 }
 
@@ -607,6 +426,9 @@
 	static unsigned char oldabs_mask[]	= { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
 	static unsigned char oldabs_rslt[]	= { 0xC0, 0x00, 0x00, 0x80, 0x00 };
 
+	if (idx < 0 || idx > 4)
+		return 0;
+
 	switch (pkt_type) {
 		case SYN_NEWABS:
 		case SYN_NEWABS_RELAXED:
@@ -637,7 +459,7 @@
 	return SYN_NEWABS_STRICT;
 }
 
-void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
 {
 	struct input_dev *dev = &psmouse->dev;
 	struct synaptics_data *priv = psmouse->private;
@@ -645,11 +467,6 @@
 	input_regs(dev, regs);
 
 	if (psmouse->pktcnt >= 6) { /* Full packet received */
-		if (priv->out_of_sync) {
-			priv->out_of_sync = 0;
-			printk(KERN_NOTICE "Synaptics driver resynced.\n");
-		}
-
 		if (unlikely(priv->pkt_type == SYN_NEWABS))
 			priv->pkt_type = synaptics_detect_pkt_type(psmouse);
 
@@ -657,16 +474,142 @@
 			synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
 		else
 			synaptics_process_packet(psmouse);
-		psmouse->pktcnt = 0;
 
-	} else if (psmouse->pktcnt &&
-		   !synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) {
-		printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt);
-		psmouse->pktcnt = 0;
-		if (++priv->out_of_sync == psmouse_resetafter) {
-			psmouse->state = PSMOUSE_IGNORE;
-			printk(KERN_NOTICE "synaptics: issuing reconnect request\n");
-			serio_reconnect(psmouse->serio);
-		}
+		return PSMOUSE_FULL_PACKET;
+	}
+
+	return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
+		PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+}
+
+/*****************************************************************************
+ *	Driver initialization/cleanup functions
+ ****************************************************************************/
+static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
+{
+	int i;
+
+	set_bit(EV_ABS, dev->evbit);
+	input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
+	input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
+	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
+	set_bit(ABS_TOOL_WIDTH, dev->absbit);
+
+	set_bit(EV_KEY, dev->evbit);
+	set_bit(BTN_TOUCH, dev->keybit);
+	set_bit(BTN_TOOL_FINGER, dev->keybit);
+	set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+	set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
+
+	set_bit(BTN_LEFT, dev->keybit);
+	set_bit(BTN_RIGHT, dev->keybit);
+
+	if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+		set_bit(BTN_MIDDLE, dev->keybit);
+
+	if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
+		set_bit(BTN_FORWARD, dev->keybit);
+		set_bit(BTN_BACK, dev->keybit);
+	}
+
+	for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
+		set_bit(BTN_0 + i, dev->keybit);
+
+	clear_bit(EV_REL, dev->evbit);
+	clear_bit(REL_X, dev->relbit);
+	clear_bit(REL_Y, dev->relbit);
+}
+
+void synaptics_reset(struct psmouse *psmouse)
+{
+	/* reset touchpad back to relative mode, gestures enabled */
+	synaptics_mode_cmd(psmouse, 0);
+}
+
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+	synaptics_reset(psmouse);
+	kfree(psmouse->private);
+}
+
+static int synaptics_reconnect(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	struct synaptics_data old_priv = *priv;
+
+	if (!synaptics_detect(psmouse))
+		return -1;
+
+	if (synaptics_query_hardware(psmouse)) {
+		printk(KERN_ERR "Unable to query Synaptics hardware.\n");
+		return -1;
+	}
+
+	if (old_priv.identity != priv->identity ||
+	    old_priv.model_id != priv->model_id ||
+	    old_priv.capabilities != priv->capabilities ||
+	    old_priv.ext_cap != priv->ext_cap)
+		return -1;
+
+	if (synaptics_set_mode(psmouse, 0)) {
+		printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int synaptics_detect(struct psmouse *psmouse)
+{
+	unsigned char param[4];
+
+	param[0] = 0;
+
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+
+	return param[1] == 0x47;
+}
+
+int synaptics_init(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv;
+
+	psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+	if (!priv)
+		return -1;
+	memset(priv, 0, sizeof(struct synaptics_data));
+
+	if (synaptics_query_hardware(psmouse)) {
+		printk(KERN_ERR "Unable to query Synaptics hardware.\n");
+		goto init_fail;
+	}
+
+	if (synaptics_set_mode(psmouse, 0)) {
+		printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
+		goto init_fail;
 	}
+
+	priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
+
+	if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+		synaptics_pt_create(psmouse);
+
+	print_ident(priv);
+	set_input_params(&psmouse->dev, priv);
+
+	psmouse->protocol_handler = synaptics_process_byte;
+	psmouse->disconnect = synaptics_disconnect;
+	psmouse->reconnect = synaptics_reconnect;
+
+	return 0;
+
+ init_fail:
+	kfree(priv);
+	return -1;
 }
+
+
--- diff/drivers/input/mouse/synaptics.h	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/synaptics.h	2004-05-27 18:34:16.000000000 +0100
@@ -9,7 +9,6 @@
 #ifndef _SYNAPTICS_H
 #define _SYNAPTICS_H
 
-extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
 extern int synaptics_detect(struct psmouse *psmouse);
 extern int synaptics_init(struct psmouse *psmouse);
 extern void synaptics_reset(struct psmouse *psmouse);
@@ -44,13 +43,14 @@
 
 /* synaptics capability bits */
 #define SYN_CAP_EXTENDED(c)		((c) & (1 << 23))
+#define SYN_CAP_MIDDLE_BUTTON(c)	((c) & (1 << 18))
 #define SYN_CAP_PASS_THROUGH(c)		((c) & (1 << 7))
 #define SYN_CAP_SLEEP(c)		((c) & (1 << 4))
 #define SYN_CAP_FOUR_BUTTON(c)		((c) & (1 << 3))
 #define SYN_CAP_MULTIFINGER(c)		((c) & (1 << 1))
 #define SYN_CAP_PALMDETECT(c)		((c) & (1 << 0))
 #define SYN_CAP_VALID(c)		((((c) & 0x00ff00) >> 8) == 0x47)
-#define SYN_EXT_CAP_REQUESTS(c)		((((c) & 0x700000) >> 20) == 1)
+#define SYN_EXT_CAP_REQUESTS(c)		(((c) & 0x700000) >> 20)
 #define SYN_CAP_MULTI_BUTTON_NO(ec)	(((ec) & 0x00f000) >> 12)
 
 /* synaptics modes query bits */
@@ -86,18 +86,12 @@
 	int y;
 	int z;
 	int w;
-	int left;
-	int right;
-	int up;
-	int down;
-	int b0;
-	int b1;
-	int b2;
-	int b3;
-	int b4;
-	int b5;
-	int b6;
-	int b7;
+	unsigned int left:1;
+	unsigned int right:1;
+	unsigned int middle:1;
+	unsigned int up:1;
+	unsigned int down:1;
+	unsigned char ext_buttons;
 };
 
 struct synaptics_data {
@@ -108,7 +102,6 @@
 	unsigned long int identity;		/* Identification */
 
 	/* Data for normal processing */
-	unsigned int out_of_sync;		/* # of packets out of sync */
 	int old_w;				/* Previous w value */
 	unsigned char pkt_type;			/* packet type - old, new, etc */
 };
--- diff/drivers/input/mousedev.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/mousedev.c	2004-05-27 18:34:16.000000000 +0100
@@ -2,6 +2,7 @@
  * Input driver to ExplorerPS/2 device driver module.
  *
  * Copyright (c) 1999-2002 Vojtech Pavlik
+ * Copyright (c) 2004      Dmitry Torokhov
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published by
@@ -47,15 +48,24 @@
 module_param(yres, uint, 0);
 MODULE_PARM_DESC(yres, "Vertical screen resolution");
 
+struct mousedev_motion {
+	int dx, dy, dz;
+};
+
 struct mousedev {
 	int exist;
 	int open;
 	int minor;
-	int misc;
 	char name[16];
 	wait_queue_head_t wait;
 	struct list_head list;
 	struct input_handle handle;
+
+	struct mousedev_motion packet;
+	unsigned long buttons;
+	unsigned int pkt_count;
+	int old_x[4], old_y[4];
+	unsigned int touch;
 };
 
 struct mousedev_list {
@@ -63,13 +73,10 @@
 	struct mousedev *mousedev;
 	struct list_head node;
 	int dx, dy, dz;
-	int old_x[4], old_y[4];
 	unsigned long buttons;
 	signed char ps2[6];
 	unsigned char ready, buffer, bufsiz;
 	unsigned char mode, imexseq, impsseq;
-	unsigned int pkt_count;
-	unsigned char touch;
 };
 
 #define MOUSEDEV_SEQ_LEN	6
@@ -82,135 +89,157 @@
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 static struct mousedev mousedev_mix;
 
-#define fx(i)  (list->old_x[(list->pkt_count - (i)) & 03])
-#define fy(i)  (list->old_y[(list->pkt_count - (i)) & 03])
+#define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
+#define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
 
-static void mousedev_abs_event(struct input_handle *handle, struct mousedev_list *list, unsigned int code, int value)
+static void mousedev_touchpad_event(struct mousedev *mousedev, unsigned int code, int value)
 {
-	int size;
-	int touchpad;
+	if (mousedev->touch) {
+		switch (code) {
+			case ABS_X:
+				fx(0) = value;
+				if (mousedev->pkt_count >= 2)
+					mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
+				break;
 
-	/* Ignore joysticks */
-	if (test_bit(BTN_TRIGGER, handle->dev->keybit))
-		return;
+			case ABS_Y:
+				fy(0) = value;
+				if (mousedev->pkt_count >= 2)
+					mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
+				break;
+		}
+	}
+}
 
-	touchpad = test_bit(BTN_TOOL_FINGER, handle->dev->keybit);
+static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
+{
+	int size;
 
 	switch (code) {
 		case ABS_X:
-			if (touchpad) {
-				if (list->touch) {
-					fx(0) = value;
-					if (list->pkt_count >= 2)
-						list->dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
-				}
-			} else {
-				size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
-				if (size == 0) size = xres;
-				list->dx += (value * xres - list->old_x[0]) / size;
-				list->old_x[0] += list->dx * size;
-			}
+			size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+			if (size == 0) size = xres;
+			mousedev->packet.dx = (value * xres - mousedev->old_x[0]) / size;
+			mousedev->old_x[0] = mousedev->packet.dx * size;
 			break;
+
 		case ABS_Y:
-			if (touchpad) {
-				if (list->touch) {
-					fy(0) = value;
-					if (list->pkt_count >= 2)
-						list->dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
-				}
-			} else {
-				size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
-				if (size == 0) size = yres;
-				list->dy -= (value * yres - list->old_y[0]) / size;
-				list->old_y[0] -= list->dy * size;
-			}
+			size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
+			if (size == 0) size = yres;
+			mousedev->packet.dy = (value * yres - mousedev->old_y[0]) / size;
+			mousedev->old_y[0] = mousedev->packet.dy * size;
 			break;
 	}
 }
 
-static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
+{
+	switch (code) {
+		case REL_X:	mousedev->packet.dx += value; break;
+		case REL_Y:	mousedev->packet.dy -= value; break;
+		case REL_WHEEL:	mousedev->packet.dz -= value; break;
+	}
+}
+
+static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
+{
+	int index;
+
+	switch (code) {
+		case BTN_TOUCH:
+		case BTN_0:
+		case BTN_FORWARD:
+		case BTN_LEFT:		index = 0; break;
+		case BTN_STYLUS:
+		case BTN_1:
+		case BTN_RIGHT:		index = 1; break;
+		case BTN_2:
+		case BTN_STYLUS2:
+		case BTN_MIDDLE:	index = 2; break;
+		case BTN_3:
+		case BTN_BACK:
+		case BTN_SIDE:		index = 3; break;
+		case BTN_4:
+		case BTN_EXTRA:		index = 4; break;
+		default: 		return;
+	}
+
+	if (value) {
+		set_bit(index, &mousedev->buttons);
+		set_bit(index, &mousedev_mix.buttons);
+	} else {
+		clear_bit(index, &mousedev->buttons);
+		clear_bit(index, &mousedev_mix.buttons);
+	}
+}
+
+static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet)
 {
-	struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
-	struct mousedev **mousedev = mousedevs;
 	struct mousedev_list *list;
-	int index, wake;
 
-	while (*mousedev) {
+	list_for_each_entry(list, &mousedev->list, node) {
+		list->dx += packet->dx;
+		list->dy += packet->dy;
+		list->dz += packet->dz;
+		list->buttons = mousedev->buttons;
+		list->ready = 1;
+		kill_fasync(&list->fasync, SIGIO, POLL_IN);
+	}
+
+	wake_up_interruptible(&mousedev->wait);
+}
+
+static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+{
+	struct mousedev *mousedev = handle->private;
+
+	switch (type) {
+		case EV_ABS:
+			/* Ignore joysticks */
+			if (test_bit(BTN_TRIGGER, handle->dev->keybit))
+				return;
+
+			if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+				mousedev_touchpad_event(mousedev, code, value);
+			else
+				mousedev_abs_event(handle->dev, mousedev, code, value);
 
-		wake = 0;
+			break;
 
-		list_for_each_entry(list, &(*mousedev)->list, node)
-			switch (type) {
-				case EV_ABS:
-					mousedev_abs_event(handle, list, code, value);
-					break;
-
-				case EV_REL:
-					switch (code) {
-						case REL_X:	list->dx += value; break;
-						case REL_Y:	list->dy -= value; break;
-						case REL_WHEEL:	if (list->mode) list->dz -= value; break;
-					}
-					break;
-
-				case EV_KEY:
-					if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {
-						/* Handle touchpad data */
-						list->touch = value;
-						if (!list->touch)
-							list->pkt_count = 0;
-						break;
-					}
-
-					switch (code) {
-						case BTN_TOUCH:
-						case BTN_0:
-						case BTN_FORWARD:
-						case BTN_LEFT:   index = 0; break;
-						case BTN_4:
-						case BTN_EXTRA:  if (list->mode == 2) { index = 4; break; }
-						case BTN_STYLUS:
-						case BTN_1:
-						case BTN_RIGHT:  index = 1; break;
-						case BTN_3:
-						case BTN_BACK:
-						case BTN_SIDE:   if (list->mode == 2) { index = 3; break; }
-						case BTN_2:
-						case BTN_STYLUS2:
-						case BTN_MIDDLE: index = 2; break;	
-						default: return;
-					}
-					switch (value) {
-						case 0: clear_bit(index, &list->buttons); break;
-						case 1: set_bit(index, &list->buttons); break;
-						case 2: return;
-					}
-					break;
-
-				case EV_SYN:
-					switch (code) {
-						case SYN_REPORT:
-							if (list->touch) {
-								list->pkt_count++;
-								/* Input system eats duplicate events,
-								 * but we need all of them to do correct
-								 * averaging so apply present one forward
-								 */
-								fx(0) = fx(1);
-								fy(0) = fy(1);
-							}
-
-							list->ready = 1;
-							kill_fasync(&list->fasync, SIGIO, POLL_IN);
-							wake = 1;
-							break;
-					}
+		case EV_REL:
+			mousedev_rel_event(mousedev, code, value);
+			break;
+
+		case EV_KEY:
+			if (value != 2) {
+				if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {
+					/* Handle touchpad data */
+					mousedev->touch = value;
+					if (!mousedev->touch)
+						mousedev->pkt_count = 0;
+				}
+				else
+					mousedev_key_event(mousedev, code, value);
 			}
+			break;
 
-		if (wake)
-			wake_up_interruptible(&((*mousedev)->wait));
+		case EV_SYN:
+			if (code == SYN_REPORT) {
+				if (mousedev->touch) {
+					mousedev->pkt_count++;
+					/* Input system eats duplicate events, but we need all of them
+					 * to do correct averaging so apply present one forward
+			 		 */
+					fx(0) = fx(1);
+					fy(0) = fy(1);
+				}
+
+				mousedev_notify_readers(mousedev, &mousedev->packet);
+				mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
 
-		mousedev++;
+				memset(&mousedev->packet, 0, sizeof(struct mousedev_motion));
+			}
+			break;
 	}
 }
 
@@ -267,7 +296,7 @@
 				mousedev_free(list->mousedev);
 		}
 	}
-	
+
 	kfree(list);
 	return 0;
 }
@@ -301,11 +330,11 @@
 		if (list->mousedev->minor == MOUSEDEV_MIX) {
 			list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
 				mousedev = handle->private;
-				if (!mousedev->open && mousedev->exist)	
+				if (!mousedev->open && mousedev->exist)
 					input_open_device(handle);
 			}
-		} else 
-			if (!mousedev_mix.open && list->mousedev->exist)	
+		} else
+			if (!mousedev_mix.open && list->mousedev->exist)
 				input_open_device(&list->mousedev->handle);
 	}
 
@@ -326,8 +355,10 @@
 		list->dz -= list->ps2[off + 3];
 		list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
 		list->bufsiz++;
+	} else {
+		list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1);
 	}
-	
+
 	if (list->mode == 1) {
 		list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
 		list->dz -= list->ps2[off + 3];
@@ -391,9 +422,9 @@
 				list->impsseq = 0;
 				list->imexseq = 0;
 				list->mode = 0;
-				list->ps2[0] = 0xaa;
-				list->ps2[1] = 0x00;
-				list->bufsiz = 2;
+				list->ps2[1] = 0xaa;
+				list->ps2[2] = 0x00;
+				list->bufsiz = 3;
 				break;
 		}
 
@@ -403,7 +434,7 @@
 	kill_fasync(&list->fasync, SIGIO, POLL_IN);
 
 	wake_up_interruptible(&list->mousedev->wait);
-		
+
 	return count;
 }
 
@@ -431,7 +462,7 @@
 	if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
 		return -EFAULT;
 
-	return count;	
+	return count;
 }
 
 /* No kernel lock - fine */
@@ -487,7 +518,7 @@
 
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor);
-	class_simple_device_add(input_class, 
+	class_simple_device_add(input_class,
 				MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
 				dev->dev, "mouse%d", minor);
 
@@ -538,7 +569,7 @@
 };
 
 MODULE_DEVICE_TABLE(input, mousedev_ids);
-	
+
 static struct input_handler mousedev_handler = {
 	.event =	mousedev_event,
 	.connect =	mousedev_connect,
@@ -553,6 +584,7 @@
 static struct miscdevice psaux_mouse = {
 	PSMOUSE_MINOR, "psaux", &mousedev_fops
 };
+static int psaux_registered;
 #endif
 
 static int __init mousedev_init(void)
@@ -572,7 +604,7 @@
 				NULL, "mice");
 
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
-	if (!(mousedev_mix.misc = !misc_register(&psaux_mouse)))
+	if (!(psaux_registered = !misc_register(&psaux_mouse)))
 		printk(KERN_WARNING "mice: could not misc_register the device\n");
 #endif
 
@@ -584,7 +616,7 @@
 static void __exit mousedev_exit(void)
 {
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
-	if (mousedev_mix.misc)
+	if (psaux_registered)
 		misc_deregister(&psaux_mouse);
 #endif
 	devfs_remove("input/mice");
--- diff/drivers/input/power.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/power.c	2004-05-27 18:34:16.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $
  *
- *  Copyright (c) 2001 "Crazy" James Simmons  
+ *  Copyright (c) 2001 "Crazy" James Simmons
  *
  *  Input driver Power Management.
  *
@@ -51,7 +51,7 @@
 
 static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL);
 
-static void power_event(struct input_handle *handle, unsigned int type, 
+static void power_event(struct input_handle *handle, unsigned int type,
 		        unsigned int code, int down)
 {
 	struct input_dev *dev = handle->dev;
@@ -73,7 +73,7 @@
 			case KEY_POWER:
 				/* Hum power down the machine. */
 				break;
-			default:	
+			default:
 				return;
 		}
 	} else {
@@ -83,9 +83,9 @@
 				/* This is risky. See pm.h for details. */
 				if (dev->state != PM_RESUME)
 					dev->state = PM_RESUME;
-				else 
-					dev->state = PM_SUSPEND;	
-				pm_send(dev->pm_dev, dev->state, dev); 	
+				else
+					dev->state = PM_SUSPEND;
+				pm_send(dev->pm_dev, dev->state, dev);
 				break;
 			case KEY_POWER:
 				/* Turn the input device off completely ? */
@@ -97,14 +97,14 @@
 	return;
 }
 
-static struct input_handle *power_connect(struct input_handler *handler, 
-					  struct input_dev *dev, 
+static struct input_handle *power_connect(struct input_handler *handler,
+					  struct input_dev *dev,
 					  struct input_device_id *id)
 {
 	struct input_handle *handle;
 
 	if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit))
-		return NULL;	
+		return NULL;
 
 	if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit)))
 		return NULL;
@@ -133,21 +133,21 @@
 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
 		.evbit = { BIT(EV_KEY) },
 		.keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) }
-	},	
+	},
 	{
 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
 		.evbit = { BIT(EV_KEY) },
 		.keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) }
-	},	
+	},
 	{
 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
 		.evbit = { BIT(EV_PWR) },
-	},	
+	},
 	{ }, 	/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE(input, power_ids);
-	
+
 static struct input_handler power_handler = {
 	.event =	power_event,
 	.connect =	power_connect,
@@ -172,3 +172,4 @@
 
 MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
 MODULE_DESCRIPTION("Input Power Management driver");
+MODULE_LICENSE("GPL");
--- diff/drivers/input/serio/98kbd-io.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/98kbd-io.c	2004-05-27 18:34:16.000000000 +0100
@@ -42,8 +42,8 @@
  * Register numbers.
  */
 
-#define KBD98_COMMAND_REG	0x43	
-#define KBD98_STATUS_REG	0x43	
+#define KBD98_COMMAND_REG	0x43
+#define KBD98_STATUS_REG	0x43
 #define KBD98_DATA_REG		0x41
 
 spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED;
@@ -51,7 +51,7 @@
 static struct serio kbd98_port;
 extern struct pt_regs *kbd_pt_regs;
 
-static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 /*
  * kbd98_flush() flushes all data that may be in the keyboard buffers
@@ -143,7 +143,7 @@
  * to the upper layers.
  */
 
-static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
 	unsigned char data;
@@ -154,6 +154,7 @@
 	spin_unlock_irqrestore(&kbd98io_lock, flags);
 	serio_interrupt(&kbd98_port, data, 0, regs);
 
+	return IRQ_HANDLED;
 }
 
 int __init kbd98io_init(void)
--- diff/drivers/input/serio/Kconfig	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/Kconfig	2004-05-27 18:34:16.000000000 +0100
@@ -97,16 +97,6 @@
 	tristate "Intel SA1111 keyboard controller"
 	depends on SA1111 && SERIO
 
-config SERIO_98KBD
-	tristate "NEC PC-9800 keyboard controller"
-	depends on X86_PC9800 && SERIO
-	help
-	  Say Y here if you have the NEC PC-9801/PC-9821 and want to use its
-	  standard keyboard connected to its keyboard controller.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called 98kbd-io.
-
 config SERIO_GSCPS2
 	tristate "HP GSC PS/2 keyboard and PS/2 mouse controller"
 	depends on GSC && SERIO
--- diff/drivers/input/serio/ct82c710.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/ct82c710.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
--- diff/drivers/input/serio/gscps2.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/gscps2.c	2004-05-27 18:34:16.000000000 +0100
@@ -16,7 +16,7 @@
  * 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.
- * 
+ *
  * TODO:
  * - Dino testing (did HP ever shipped a machine on which this port
  *                 was usable/enabled ?)
@@ -44,7 +44,7 @@
 
 #define PFX "gscps2.c: "
 
-/* 
+/*
  * Driver constants
  */
 
@@ -222,7 +222,7 @@
 /**
  * gscps2_interrupt() - Interruption service routine
  *
- * This function reads received PS/2 bytes and processes them on 
+ * This function reads received PS/2 bytes and processes them on
  * all interfaces.
  * The problematic part here is, that the keyboard and mouse PS/2 port
  * share the same interrupt and it's not possible to send data if any
@@ -240,9 +240,9 @@
 	  unsigned long flags;
 	  spin_lock_irqsave(&ps2port->lock, flags);
 
-	  while ( (ps2port->buffer[ps2port->append].str = 
+	  while ( (ps2port->buffer[ps2port->append].str =
 		   gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) {
-		ps2port->buffer[ps2port->append].data = 
+		ps2port->buffer[ps2port->append].data =
 				gscps2_readb_input(ps2port->addr);
 		ps2port->append = ((ps2port->append+1) & BUFFER_SIZE);
 	  }
@@ -349,7 +349,7 @@
 
 	if (!dev->irq)
 		return -ENODEV;
-	
+
 	/* Offset for DINO PS/2. Works with LASI even */
 	if (dev->id.sversion == 0x96)
 		hpa += GSC_DINO_OFFSET;
@@ -368,7 +368,7 @@
 	gscps2_reset(ps2port);
 	ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f;
 	snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s",
-		gscps2_serio_port.name, 
+		gscps2_serio_port.name,
 		(ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" );
 
 	memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port));
@@ -401,9 +401,9 @@
 		ps2port->port.phys);
 
 	serio_register_port(&ps2port->port);
-	
+
 	return 0;
-	
+
 fail:
 	free_irq(dev->irq, ps2port);
 
@@ -430,7 +430,7 @@
 	list_del(&ps2port->node);
 	iounmap(ps2port->addr);
 #if 0
-	release_mem_region(dev->hpa, GSC_STATUS + 4); 
+	release_mem_region(dev->hpa, GSC_STATUS + 4);
 #endif
 	dev_set_drvdata(&dev->dev, NULL);
 	kfree(ps2port);
@@ -441,7 +441,7 @@
 static struct parisc_device_id gscps2_device_tbl[] = {
 	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */
 #ifdef DINO_TESTED
-	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ 
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */
 #endif
 	{ 0, }	/* 0 terminated list */
 };
--- diff/drivers/input/serio/i8042.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/i8042.c	2004-05-27 18:34:16.000000000 +0100
@@ -32,7 +32,7 @@
 module_param_named(noaux, i8042_noaux, bool, 0);
 MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
 
-static unsigned int i8042_nomux;
+unsigned int i8042_nomux;
 module_param_named(nomux, i8042_nomux, bool, 0);
 MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present.");
 
@@ -150,7 +150,7 @@
  */
 
 static int i8042_command(unsigned char *param, int command)
-{ 
+{
 	unsigned long flags;
 	int retval = 0, i = 0;
 
@@ -161,7 +161,7 @@
 		dbg("%02x -> i8042 (command)", command & 0xff);
 		i8042_write_command(command & 0xff);
 	}
-	
+
 	if (!retval)
 		for (i = 0; i < ((command >> 12) & 0xf); i++) {
 			if ((retval = i8042_wait_write())) break;
@@ -172,7 +172,7 @@
 	if (!retval)
 		for (i = 0; i < ((command >> 8) & 0xf); i++) {
 			if ((retval = i8042_wait_read())) break;
-			if (i8042_read_status() & I8042_STR_AUXDATA) 
+			if (i8042_read_status() & I8042_STR_AUXDATA)
 				param[i] = ~i8042_read_data();
 			else
 				param[i] = i8042_read_data();
@@ -415,17 +415,17 @@
 		} else dfl = 0;
 
 		dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)",
-			data, (str >> 6), irq, 
+			data, (str >> 6), irq,
 			dfl & SERIO_PARITY ? ", bad parity" : "",
 			dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
 		serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs);
-		
+
 		goto irq_ret;
 	}
 
 	dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
-		data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, 
+		data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq,
 		dfl & SERIO_PARITY ? ", bad parity" : "",
 		dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
@@ -474,8 +474,17 @@
 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
 		return -1;
 	param = 0xa4;
-	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b) {
+
+/*
+ * Do another loop test with the 0x5a value. Doing anything else upsets
+ * Profusion/ServerWorks OSB4 chipsets.
+ */
+
+		param = 0x5a;
+		i8042_command(&param, I8042_CMD_AUX_LOOP);
 		return -1;
+	}
 
 	if (mux_version)
 		*mux_version = ~param;
@@ -530,10 +539,10 @@
 
 	if (i8042_enable_mux_mode(values, &mux_version))
 		return -1;
-	
+
 	/* Workaround for broken chips which seem to support MUX, but in reality don't. */
-	/* They all report version 12.10 */
-	if (mux_version == 0xCA)
+	/* They all report version 10.12 */
+	if (mux_version == 0xAC)
 		return -1;
 
 	printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
@@ -598,7 +607,7 @@
 /*
  * Bit assignment test - filters out PS/2 i8042's in AT mode
  */
-	
+
 	if (i8042_command(&param, I8042_CMD_AUX_DISABLE))
 		return -1;
 	if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) {
@@ -609,7 +618,7 @@
 	if (i8042_command(&param, I8042_CMD_AUX_ENABLE))
 		return -1;
 	if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS))
-		return -1;	
+		return -1;
 
 /*
  * Disable the interface.
@@ -639,7 +648,7 @@
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
 		printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n");
 		values->exists = 0;
-		return -1; 
+		return -1;
 	}
 
 	printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
@@ -868,7 +877,7 @@
 static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
         		    void *unused)
 {
-        if (code==SYS_DOWN || code==SYS_HALT) 
+        if (code == SYS_DOWN || code == SYS_HALT)
         	i8042_controller_cleanup();
         return NOTIFY_DONE;
 }
@@ -997,20 +1006,20 @@
 		sysdev_class_unregister(&kbc_sysclass);
 	}
 
-	del_timer_sync(&i8042_timer);
-
 	i8042_controller_cleanup();
-	
+
 	if (i8042_kbd_values.exists)
 		serio_unregister_port(&i8042_kbd_port);
 
 	if (i8042_aux_values.exists)
 		serio_unregister_port(&i8042_aux_port);
-	
+
 	for (i = 0; i < 4; i++)
 		if (i8042_mux_values[i].exists)
 			serio_unregister_port(i8042_mux_port + i);
 
+	del_timer_sync(&i8042_timer);
+
 	i8042_platform_exit();
 }
 
--- diff/drivers/input/serio/parkbd.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/parkbd.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -86,20 +86,9 @@
 	return 0;
 }
 
-static int parkbd_open(struct serio *port)
-{
-	return 0;
-}
-
-static void parkbd_close(struct serio *port)
-{
-}
-
 static struct serio parkbd_port =
 {
 	.write	= parkbd_write,
-	.open	= parkbd_open,
-	.close	= parkbd_close,
 	.name	= parkbd_name,
 	.phys	= parkbd_phys,
 };
@@ -115,7 +104,7 @@
 			parkbd_writing = 0;
 			parkbd_writelines(3);
 			return;
-		}	
+		}
 
 		parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2);
 
@@ -131,7 +120,7 @@
 		if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) {
 			parkbd_counter = 0;
 			parkbd_buffer = 0;
-		}	
+		}
 
 		parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
 
--- diff/drivers/input/serio/q40kbd.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/q40kbd.c	2004-05-27 18:34:16.000000000 +0100
@@ -4,7 +4,7 @@
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
  *  Based on the work of:
- *	Richard Zidlicky <Richard.Zidlicky@stud.informatik.uni-erlangen.de>	
+ *	Richard Zidlicky <Richard.Zidlicky@stud.informatik.uni-erlangen.de>
  */
 
 /*
@@ -47,23 +47,12 @@
 MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
 MODULE_LICENSE("GPL");
 
-
-static int q40kbd_open(struct serio *port)
-{
-	return 0;
-}
-static void q40kbd_close(struct serio *port)
-{
-}
-
 static struct serio q40kbd_port =
 {
 	.type	= SERIO_8042,
 	.name	= "Q40 kbd port",
 	.phys	= "Q40",
 	.write	= NULL,
-	.open	= q40kbd_open,
-	.close	= q40kbd_close,
 };
 
 static irqreturn_t q40kbd_interrupt(int irq, void *dev_id,
--- diff/drivers/input/serio/rpckbd.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/rpckbd.c	2004-05-27 18:34:16.000000000 +0100
@@ -98,7 +98,7 @@
 static void rpckbd_close(struct serio *port)
 {
 	free_irq(IRQ_KEYBOARDRX, port);
-	free_irq(IRQ_KEYBOARDTX, port);	
+	free_irq(IRQ_KEYBOARDTX, port);
 }
 
 static struct serio rpckbd_port =
--- diff/drivers/input/serio/sa1111ps2.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/sa1111ps2.c	2004-05-27 18:34:16.000000000 +0100
@@ -45,7 +45,6 @@
 {
 	struct ps2if *ps2if = dev_id;
 	unsigned int scancode, flag, status;
-	int handled = IRQ_NONE;
 
 	status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
 	while (status & PS2STAT_RXF) {
@@ -63,11 +62,9 @@
 		serio_interrupt(&ps2if->io, scancode, flag, regs);
 
 		status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
-
-		handled = IRQ_HANDLED;
         }
 
-        return handled;
+        return IRQ_HANDLED;
 }
 
 /*
--- diff/drivers/input/serio/serio.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/serio.c	2004-05-27 18:34:16.000000000 +0100
@@ -11,18 +11,18 @@
 /*
  * 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 
+ * 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
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -108,7 +108,7 @@
 	struct serio_event *event;
 
 	list_for_each_safe(node, next, &serio_event_list) {
-		event = container_of(node, struct serio_event, node);	
+		event = container_of(node, struct serio_event, node);
 
 		down(&serio_sem);
 		if (event->serio == NULL)
@@ -152,7 +152,7 @@
 
 	do {
 		serio_handle_events();
-		wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); 
+		wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
 		if (current->flags & PF_FREEZE)
 			refrigerator(PF_FREEZE);
 	} while (!signal_pending(current));
@@ -195,9 +195,6 @@
                 ret = serio->dev->interrupt(serio, data, flags, regs);
 	} else {
 		if (!flags) {
-			if ((serio->type == SERIO_8042 ||
-				serio->type == SERIO_8042_XL) && (data != 0xaa))
-					return ret;
 			serio_rescan(serio);
 			ret = IRQ_HANDLED;
 		}
@@ -293,7 +290,7 @@
 int serio_open(struct serio *serio, struct serio_dev *dev)
 {
 	serio->dev = dev;
-	if (serio->open(serio)) {
+	if (serio->open && serio->open(serio)) {
 		serio->dev = NULL;
 		return -1;
 	}
@@ -303,7 +300,8 @@
 /* called from serio_dev->connect/disconnect methods under serio_sem */
 void serio_close(struct serio *serio)
 {
-	serio->close(serio);
+	if (serio->close)
+		serio->close(serio);
 	serio->dev = NULL;
 }
 
--- diff/drivers/input/serio/serport.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/serport.c	2004-05-27 18:34:16.000000000 +0100
@@ -48,11 +48,6 @@
 	return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1);
 }
 
-static int serport_serio_open(struct serio *serio)
-{
-        return 0;
-}
-
 static void serport_serio_close(struct serio *serio)
 {
 	struct serport *serport = serio->driver;
@@ -87,7 +82,6 @@
 
 	serport->serio.type = SERIO_RS232;
 	serport->serio.write = serport_serio_write;
-	serport->serio.open = serport_serio_open;
 	serport->serio.close = serport_serio_close;
 	serport->serio.driver = serport;
 
@@ -135,7 +129,7 @@
 }
 
 /*
- * serport_ldisc_read() just waits indefinitely if everything goes well. 
+ * serport_ldisc_read() just waits indefinitely if everything goes well.
  * However, when the serio driver closes the serio port, it finishes,
  * returning 0 characters.
  */
@@ -165,7 +159,7 @@
 static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
 	struct serport *serport = (struct serport*) tty->disc_data;
-	
+
 	if (cmd == SPIOCSTYPE)
 		return get_user(serport->serio.type, (unsigned long *) arg);
 
--- diff/drivers/input/touchscreen/gunze.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/touchscreen/gunze.c	2004-05-27 18:34:16.000000000 +0100
@@ -124,12 +124,10 @@
 	memset(gunze, 0, sizeof(struct gunze));
 
 	init_input_dev(&gunze->dev);
-	gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
-	gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+	gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 	gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-
-	gunze->dev.absmin[ABS_X] = 96;   gunze->dev.absmin[ABS_Y] = 72;
-	gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000;
+	input_set_abs_params(&gunze->dev, ABS_X, 96, 4000, 0, 0);
+	input_set_abs_params(&gunze->dev, ABS_Y, 72, 3000, 0, 0);
 
 	gunze->serio = serio;
 	serio->private = gunze;
--- diff/drivers/input/touchscreen/h3600_ts_input.c	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/touchscreen/h3600_ts_input.c	2004-05-27 18:34:16.000000000 +0100
@@ -1,11 +1,11 @@
 /*
  * $Id: h3600_ts_input.c,v 1.4 2002/01/23 06:39:37 jsimmons Exp $
  *
- *  Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com 
+ *  Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com
  *
- *  Sponsored by Transvirtual Technology. 
- * 
- *  Derived from the code in h3600_ts.[ch] by Charles Flynn  
+ *  Sponsored by Transvirtual Technology.
+ *
+ *  Derived from the code in h3600_ts.[ch] by Charles Flynn
  */
 
 /*
@@ -45,6 +45,10 @@
 #include <asm/arch/hardware.h>
 #include <asm/arch/irqs.h>
 
+MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
+MODULE_DESCRIPTION("H3600 touchscreen driver");
+MODULE_LICENSE("GPL");
+
 /*
  * Definitions & global arrays.
  */
@@ -75,7 +79,7 @@
 #define MAX_ID                  14
 
 #define H3600_MAX_LENGTH 16
-#define H3600_KEY 0xf 
+#define H3600_KEY 0xf
 
 #define H3600_SCANCODE_RECORD	1	 /* 1 -> record button */
 #define H3600_SCANCODE_CALENDAR 2	 /* 2 -> calendar */
@@ -103,7 +107,7 @@
 	char phys[32];
 };
 
-static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
         int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
 	struct input_dev *dev = (struct input_dev *) dev_id;
@@ -111,21 +115,25 @@
 	input_regs(dev, regs);
 	input_report_key(dev, KEY_ENTER, down);
 	input_sync(dev);
+
+	return IRQ_HANDLED;
 }
 
-static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
         int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
 	struct input_dev *dev = (struct input_dev *) dev_id;
 
-	/* 
-	 * This interrupt is only called when we release the key. So we have 
+	/*
+	 * This interrupt is only called when we release the key. So we have
 	 * to fake a key press.
-	 */ 	
+	 */
 	input_regs(dev, regs);
 	input_report_key(dev, KEY_SUSPEND, 1);
-	input_report_key(dev, KEY_SUSPEND, down); 	
+	input_report_key(dev, KEY_SUSPEND, down);
 	input_sync(dev);
+
+	return IRQ_HANDLED;
 }
 
 #ifdef CONFIG_PM
@@ -141,21 +149,21 @@
  * h3600_flite_power: enables or disables power to frontlight, using last bright */
 unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
 {
-	unsigned char brightness = ((pwr==FLITE_PWR_OFF) ? 0:flite_brightness);
+	unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
 	struct h3600_dev *ts = dev->private;
 
-	/* Must be in this order */	
+	/* Must be in this order */
        	ts->serio->write(ts->serio, 1);
 	ts->serio->write(ts->serio, pwr);
-      	ts->serio->write(ts->serio, brightness); 
+      	ts->serio->write(ts->serio, brightness);
 	return 0;
 }
 
 static int suspended = 0;
-static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, 
+static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
 				void *data)
 {
-	struct input_dev *dev = (struct input_dev *) data;	
+	struct input_dev *dev = (struct input_dev *) data;
 
         switch (req) {
         case PM_SUSPEND: /* enter D1-D3 */
@@ -183,7 +191,7 @@
 /*
  * This function translates the native event packets to linux input event
  * packets. Some packets coming from serial are not touchscreen related. In
- * this case we send them off to be processed elsewhere. 
+ * this case we send them off to be processed elsewhere.
  */
 static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
 {
@@ -206,7 +214,7 @@
                 Note: This is true for non interrupt generated key events.
                 */
                 case KEYBD_ID:
-			down = (ts->buf[0] & 0x80) ? 0 : 1; 
+			down = (ts->buf[0] & 0x80) ? 0 : 1;
 
 			switch (ts->buf[0] & 0x7f) {
 				case H3600_SCANCODE_RECORD:
@@ -218,7 +226,7 @@
 				case H3600_SCANCODE_CONTACTS:
 					key = KEY_PROG2;
                                         break;
-				case H3600_SCANCODE_Q:        
+				case H3600_SCANCODE_Q:
 					key = KEY_Q;
                                         break;
 				case H3600_SCANCODE_START:
@@ -237,9 +245,9 @@
 					key = KEY_DOWN;
                                         break;
 				default:
-					key = 0;	
-			}	
-                        if (key) 
+					key = 0;
+			}
+                        if (key)
                         	input_report_key(dev, key, down);
                         break;
                 /*
@@ -251,13 +259,13 @@
                  *       byte 0    1       2       3
                  */
                 case TOUCHS_ID:
-			if (!touched) { 
+			if (!touched) {
 				input_report_key(dev, BTN_TOUCH, 1);
 				touched = 1;
-			}			
+			}
 
 			if (ts->len) {
-				unsigned short x, y;				
+				unsigned short x, y;
 
 				x = ts->buf[0]; x <<= 8; x += ts->buf[1];
                                 y = ts->buf[2]; y <<= 8; y += ts->buf[3];
@@ -267,7 +275,7 @@
 			} else {
 		               	input_report_key(dev, BTN_TOUCH, 0);
 				touched = 0;
-			}	
+			}
                         break;
 		default:
 			/* Send a non input event elsewhere */
@@ -280,7 +288,7 @@
 /*
  * h3600ts_event() handles events from the input module.
  */
-static int h3600ts_event(struct input_dev *dev, unsigned int type, 
+static int h3600ts_event(struct input_dev *dev, unsigned int type,
 		 	 unsigned int code, int value)
 {
 	struct h3600_dev *ts = dev->private;
@@ -290,7 +298,7 @@
 		//	ts->serio->write(ts->serio, SOME_CMD);
 			return 0;
 		}
-	}					
+	}
 	return -1;
 }
 
@@ -317,19 +325,19 @@
 #define STATE_DATA      2       /* state where we decode data */
 #define STATE_EOF       3       /* state where we decode checksum or EOF */
 
-static void h3600ts_interrupt(struct serio *serio, unsigned char data,
-                              unsigned int flags)
+static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
+                                     unsigned int flags, struct pt_regs *regs)
 {
         struct h3600_dev *ts = serio->private;
 
 	/*
-         * We have a new frame coming in. 
+         * We have a new frame coming in.
          */
 	switch (state) {
 		case STATE_SOF:
         		if (data == CHAR_SOF)
-                		state = STATE_ID;	
-			return;
+                		state = STATE_ID;
+			break;
         	case STATE_ID:
 			ts->event = (data & 0xf0) >> 4;
 			ts->len = (data & 0xf);
@@ -339,23 +347,25 @@
                         	break;
 			}
 			ts->chksum = data;
-                	state=(ts->len > 0 ) ? STATE_DATA : STATE_EOF;
+                	state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
 			break;
 		case STATE_DATA:
 			ts->chksum += data;
 			ts->buf[ts->idx]= data;
-			if(++ts->idx == ts->len) 
+			if(++ts->idx == ts->len)
                         	state = STATE_EOF;
 			break;
 		case STATE_EOF:
                 	state = STATE_SOF;
-                	if (data == CHAR_EOF || data == ts->chksum )
-				h3600ts_process_packet(ts);
+                	if (data == CHAR_EOF || data == ts->chksum)
+				h3600ts_process_packet(ts, regs);
                 	break;
         	default:
                 	printk("Error3\n");
                 	break;
 	}
+
+	return IRQ_HANDLED;
 }
 
 /*
@@ -378,11 +388,11 @@
 	init_input_dev(&ts->dev);
 
 	/* Device specific stuff */
-        set_GPIO_IRQ_edge( GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES );
-        set_GPIO_IRQ_edge( GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE );
+        set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
+        set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 
         if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
-			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,	
+			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
 			"h3600_action", &ts->dev)) {
 		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
 		kfree(ts);
@@ -390,24 +400,19 @@
 	}
 
         if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
-			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, 
+			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
 			"h3600_suspend", &ts->dev)) {
 		free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
 		printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
 		kfree(ts);
 		return;
 	}
+
 	/* Now we have things going we setup our input device */
 	ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR);
-	ts->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-	ts->dev.ledbit[0] = BIT(LED_SLEEP); 
-
-	ts->dev.absmin[ABS_X] = 60;   ts->dev.absmin[ABS_Y] = 35;
-	ts->dev.absmax[ABS_X] = 985; ts->dev.absmax[ABS_Y] = 1024;
-	ts->dev.absfuzz[ABS_X] = 0; ts->dev.absfuzz[ABS_Y] = 0;
-
-	ts->serio = serio;
-	serio->private = ts;
+	ts->dev.ledbit[0] = BIT(LED_SLEEP);
+	input_set_abs_params(&ts->dev, ABS_X, 60, 985, 0, 0);
+	input_set_abs_params(&ts->dev, ABS_Y, 35, 1024, 0, 0);
 
 	set_bit(KEY_RECORD, ts->dev.keybit);
 	set_bit(KEY_Q, ts->dev.keybit);
@@ -422,6 +427,9 @@
 	ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
 	ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
 
+	ts->serio = serio;
+	serio->private = ts;
+
 	sprintf(ts->phys, "%s/input0", serio->phys);
 
        	ts->dev.event = h3600ts_event;
@@ -442,7 +450,7 @@
 
 	//h3600_flite_control(1, 25);     /* default brightness */
 #ifdef CONFIG_PM
-	ts->dev.pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT, 
+	ts->dev.pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT,
 					h3600ts_pm_callback);
 	printk("registered pm callback\n");
 #endif
@@ -458,7 +466,7 @@
 static void h3600ts_disconnect(struct serio *serio)
 {
 	struct h3600_dev *ts = serio->private;
-	
+
         free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
         free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
 	input_unregister_device(&ts->dev);
--- diff/drivers/input/tsdev.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/tsdev.c	2004-05-27 18:34:16.000000000 +0100
@@ -3,9 +3,17 @@
  *
  *  Copyright (c) 2001 "Crazy" james Simmons 
  *
- *  Input driver to Touchscreen device driver module.
+ *  Compaq touchscreen protocol driver. The protocol emulated by this driver
+ *  is obsolete; for new programs use the tslib library which can read directly
+ *  from evdev and perform dejittering, variance filtering and calibration -
+ *  all in user space, not at kernel level. The meaning of this driver is
+ *  to allow usage of newer input drivers with old applications that use the
+ *  old /dev/h3600_ts and /dev/h3600_tsraw devices.
  *
- *  Sponsored by Transvirtual Technology
+ *  09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
+ *      Fixed to actually work, not just output random numbers.
+ *      Added support for both h3600_ts and h3600_tsraw protocol
+ *      emulation.
  */
 
 /*
@@ -24,11 +32,13 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <jsimmons@transvirtual.com>.
+ * e-mail - mail your message to <jsimmons@infradead.org>.
  */
 
 #define TSDEV_MINOR_BASE 	128
 #define TSDEV_MINORS		32
+/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
+#define TSDEV_MINOR_MASK	15
 #define TSDEV_BUFFER_SIZE	64
 
 #include <linux/slab.h>
@@ -52,48 +62,84 @@
 #define CONFIG_INPUT_TSDEV_SCREEN_Y	320
 #endif
 
+/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
+ * devices. The first one must output X/Y data in 'cooked' format, e.g.
+ * filtered, dejittered and calibrated. Second device just outputs raw
+ * data received from the hardware.
+ *
+ * This driver doesn't support filtering and dejittering; it supports only
+ * calibration. Filtering and dejittering must be done in the low-level
+ * driver, if needed, because it may gain additional benefits from knowing
+ * the low-level details, the nature of noise and so on.
+ *
+ * The driver precomputes a calibration matrix given the initial xres and
+ * yres values (quite innacurate for most touchscreens) that will result
+ * in a more or less expected range of output values. The driver supports
+ * the TS_SET_CAL ioctl, which will replace the calibration matrix with a
+ * new one, supposedly generated from the values taken from the raw device.
+ */
+
 MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
 MODULE_DESCRIPTION("Input driver to touchscreen converter");
 MODULE_LICENSE("GPL");
 
 static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
 module_param(xres, uint, 0);
-MODULE_PARM_DESC(xres, "Horizontal screen resolution");
+MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
 
 static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
 module_param(yres, uint, 0);
-MODULE_PARM_DESC(yres, "Vertical screen resolution");
+MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)");
+
+/* From Compaq's Touch Screen Specification version 0.2 (draft) */
+struct ts_event {
+	short pressure;
+	short x;
+	short y;
+	short millisecs;
+};
+
+struct ts_calibration {
+	int xscale;
+	int xtrans;
+	int yscale;
+	int ytrans;
+	int xyswap;
+};
 
 struct tsdev {
 	int exist;
 	int open;
 	int minor;
-	char name[16];
+	char name[8];
 	wait_queue_head_t wait;
 	struct list_head list;
 	struct input_handle handle;
+	int x, y, pressure;
+	struct ts_calibration cal;
 };
 
-/* From Compaq's Touch Screen Specification version 0.2 (draft) */
-typedef struct {
-	short pressure;
-	short x;
-	short y;
-	short millisecs;
-} TS_EVENT;
-
 struct tsdev_list {
 	struct fasync_struct *fasync;
 	struct list_head node;
 	struct tsdev *tsdev;
 	int head, tail;
-	int oldx, oldy, pendown;
-	TS_EVENT event[TSDEV_BUFFER_SIZE];
+	struct ts_event event[TSDEV_BUFFER_SIZE];
+	int raw;
 };
 
+/* The following ioctl codes are defined ONLY for backward compatibility.
+ * Don't use tsdev for new developement; use the tslib library instead.
+ * Touchscreen calibration is a fully userspace task.
+ */
+/* Use 'f' as magic number */
+#define IOC_H3600_TS_MAGIC  'f'
+#define TS_GET_CAL	_IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
+#define TS_SET_CAL	_IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
+
 static struct input_handler tsdev_handler;
 
-static struct tsdev *tsdev_table[TSDEV_MINORS];
+static struct tsdev *tsdev_table[TSDEV_MINORS/2];
 
 static int tsdev_fasync(int fd, struct file *file, int on)
 {
@@ -109,13 +155,16 @@
 	int i = iminor(inode) - TSDEV_MINOR_BASE;
 	struct tsdev_list *list;
 
-	if (i >= TSDEV_MINORS || !tsdev_table[i])
+	if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
 		return -ENODEV;
 
 	if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
 		return -ENOMEM;
 	memset(list, 0, sizeof(struct tsdev_list));
 
+	list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
+
+	i &= TSDEV_MINOR_MASK;
 	list->tsdev = tsdev_table[i];
 	list_add_tail(&list->node, &tsdev_table[i]->list);
 	file->private_data = list;
@@ -169,11 +218,13 @@
 	if (!list->tsdev->exist)
 		return -ENODEV;
 
-	while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) {
-		if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT)))
+	while (list->head != list->tail &&
+	       retval + sizeof (struct ts_event) <= count) {
+		if (copy_to_user (buffer + retval, list->event + list->tail,
+				  sizeof (struct ts_event)))
 			return -EFAULT;
 		list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
-		retval += sizeof(TS_EVENT);
+		retval += sizeof (struct ts_event);
 	}
 
 	return retval;
@@ -193,22 +244,27 @@
 static int tsdev_ioctl(struct inode *inode, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
-/*
 	struct tsdev_list *list = file->private_data;
-        struct tsdev *evdev = list->tsdev;
-        struct input_dev *dev = tsdev->handle.dev;
-        int retval;
-	
+	struct tsdev *tsdev = list->tsdev;
+	int retval = 0;
+
 	switch (cmd) {
-		case HHEHE:
-			return 0;
-		case hjff:
-			return 0;
-		default:
-			return 0;
+	case TS_GET_CAL:
+		if (copy_to_user ((void *)arg, &tsdev->cal,
+				  sizeof (struct ts_calibration)))
+			retval = -EFAULT;
+		break;
+	case TS_SET_CAL:
+		if (copy_from_user (&tsdev->cal, (void *)arg,
+				    sizeof (struct ts_calibration)))
+			retval = -EFAULT;
+		break;
+	default:
+		retval = -EINVAL;
+		break;
 	}
-*/
-	return -EINVAL;
+
+	return retval;
 }
 
 struct file_operations tsdev_fops = {
@@ -227,82 +283,85 @@
 	struct tsdev *tsdev = handle->private;
 	struct tsdev_list *list;
 	struct timeval time;
-	int size;
 
-	list_for_each_entry(list, &tsdev->list, node) {
-		switch (type) {
-		case EV_ABS:
-			switch (code) {
-			case ABS_X:
-				if (!list->pendown)
-					return;
-				size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
-				if (size > 0)
-					list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size);
-				else
-					list->oldx = ((value - handle->dev->absmin[ABS_X]));
-				break;
-			case ABS_Y:
-				if (!list->pendown)
-					return;
-				size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
-				if (size > 0)
-					list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size);
-				else
-					list->oldy = ((value - handle->dev->absmin[ABS_Y]));
-				break;
-			case ABS_PRESSURE:
-				list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ?
-				    value - handle->dev->absmin[ABS_PRESSURE] : 0;
-				break;
-			}
+	switch (type) {
+	case EV_ABS:
+		switch (code) {
+		case ABS_X:
+			tsdev->x = value;
+			break;
+		case ABS_Y:
+			tsdev->y = value;
+			break;
+		case ABS_PRESSURE:
+			if (value > handle->dev->absmax[ABS_PRESSURE])
+				value = handle->dev->absmax[ABS_PRESSURE];
+			value -= handle->dev->absmin[ABS_PRESSURE];
+			if (value < 0)
+				value = 0;
+			tsdev->pressure = value;
+			break;
+		}
+		break;
+
+	case EV_REL:
+		switch (code) {
+		case REL_X:
+			tsdev->x += value;
+			if (tsdev->x < 0)
+				tsdev->x = 0;
+			else if (tsdev->x > xres)
+				tsdev->x = xres;
+			break;
+		case REL_Y:
+			tsdev->y += value;
+			if (tsdev->y < 0)
+				tsdev->y = 0;
+			else if (tsdev->y > yres)
+				tsdev->y = yres;
 			break;
+		}
+		break;
 
-		case EV_REL:
-			switch (code) {
-			case REL_X:
-				if (!list->pendown)
-					return;
-				list->oldx += value;
-				if (list->oldx < 0)
-					list->oldx = 0;
-				else if (list->oldx > xres)
-					list->oldx = xres;
+	case EV_KEY:
+		if (code == BTN_TOUCH || code == BTN_MOUSE) {
+			switch (value) {
+			case 0:
+				tsdev->pressure = 0;
 				break;
-			case REL_Y:
-				if (!list->pendown)
-					return;
-				list->oldy += value;
-				if (list->oldy < 0)
-					list->oldy = 0;
-				else if (list->oldy > xres)
-					list->oldy = xres;
+			case 1:
+				if (!tsdev->pressure)
+					tsdev->pressure = 1;
 				break;
 			}
-			break;
-
-		case EV_KEY:
-			if (code == BTN_TOUCH || code == BTN_MOUSE) {
-				switch (value) {
-				case 0:
-					list->pendown = 0;
-					break;
-				case 1:
-					if (!list->pendown)
-						list->pendown = 1;
-					break;
-				case 2:
-					return;
-				}
-			} else
-				return;
-			break;
 		}
+		break;
+	}
+
+	if (type != EV_SYN || code != SYN_REPORT)
+		return;
+
+	list_for_each_entry(list, &tsdev->list, node) {
+		int x, y, tmp;
+
 		do_gettimeofday(&time);
 		list->event[list->head].millisecs = time.tv_usec / 100;
-		list->event[list->head].pressure = list->pendown;
-		list->event[list->head].x = list->oldx;
-		list->event[list->head].y = list->oldy;
+		list->event[list->head].pressure = tsdev->pressure;
+
+		x = tsdev->x;
+		y = tsdev->y;
+
+		/* Calibration */
+		if (!list->raw) {
+			x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
+			y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
+			if (tsdev->cal.xyswap) {
+				tmp = x; x = y; y = tmp;
+			}
+		}
+
+		list->event[list->head].x = x;
+		list->event[list->head].y = y;
 		list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
 		kill_fasync(&list->fasync, SIGIO, POLL_IN);
 	}
@@ -314,11 +373,11 @@
 					  struct input_device_id *id)
 {
 	struct tsdev *tsdev;
-	int minor;
+	int minor, delta;
 
-	for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor];
+	for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor];
 	     minor++);
-	if (minor == TSDEV_MINORS) {
+	if (minor >= TSDEV_MINORS/2) {
 		printk(KERN_ERR
 		       "tsdev: You have way too many touchscreens\n");
 		return NULL;
@@ -340,10 +399,25 @@
 	tsdev->handle.handler = handler;
 	tsdev->handle.private = tsdev;
 
+	/* Precompute the rough calibration matrix */
+	delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
+	if (delta == 0)
+		delta = 1;
+	tsdev->cal.xscale = (xres << 8) / delta;
+	tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
+
+	delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
+	if (delta == 0)
+		delta = 1;
+	tsdev->cal.yscale = (yres << 8) / delta;
+	tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
+
 	tsdev_table[minor] = tsdev;
-	
+
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor);
+	devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2),
+			S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor);
 	class_simple_device_add(input_class, 
 				MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
 				dev->dev, "ts%d", minor);
@@ -362,6 +436,7 @@
 		wake_up_interruptible(&tsdev->wait);
 	} else
 		tsdev_free(tsdev);
+	devfs_remove("input/tsraw%d", tsdev->minor);
 }
 
 static struct input_device_id tsdev_ids[] = {
@@ -379,6 +454,12 @@
 	      .absbit	= { BIT(ABS_X) | BIT(ABS_Y) },
 	 },/* A tablet like device, at least touch detection, two absolute axes */
 
+	{
+	      .flags	= INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+	      .evbit	= { BIT(EV_ABS) },
+	      .absbit	= { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
+	 },/* A tablet like device with several gradations of pressure */
+
 	{},/* Terminating entry */
 };
 
--- diff/drivers/md/dm-ioctl.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/dm-ioctl.c	2004-05-27 18:34:16.000000000 +0100
@@ -46,7 +46,7 @@
 static struct list_head _name_buckets[NUM_BUCKETS];
 static struct list_head _uuid_buckets[NUM_BUCKETS];
 
-void dm_hash_remove_all(void);
+static void dm_hash_remove_all(void);
 
 /*
  * Guards access to both hash tables.
@@ -61,7 +61,7 @@
 		INIT_LIST_HEAD(buckets + i);
 }
 
-int dm_hash_init(void)
+static int dm_hash_init(void)
 {
 	init_buckets(_name_buckets);
 	init_buckets(_uuid_buckets);
@@ -69,7 +69,7 @@
 	return 0;
 }
 
-void dm_hash_exit(void)
+static void dm_hash_exit(void)
 {
 	dm_hash_remove_all();
 	devfs_remove(DM_DIR);
@@ -195,7 +195,7 @@
  * The kdev_t and uuid of a device can never change once it is
  * initially inserted.
  */
-int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
+static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
 {
 	struct hash_cell *cell;
 
@@ -234,7 +234,7 @@
 	return -EBUSY;
 }
 
-void __hash_remove(struct hash_cell *hc)
+static void __hash_remove(struct hash_cell *hc)
 {
 	/* remove from the dev hash */
 	list_del(&hc->uuid_list);
@@ -246,7 +246,7 @@
 	free_cell(hc);
 }
 
-void dm_hash_remove_all(void)
+static void dm_hash_remove_all(void)
 {
 	int i;
 	struct hash_cell *hc;
@@ -262,7 +262,7 @@
 	up_write(&_hash_lock);
 }
 
-int dm_hash_rename(const char *old, const char *new)
+static int dm_hash_rename(const char *old, const char *new)
 {
 	char *new_name, *old_name;
 	struct hash_cell *hc;
@@ -377,7 +377,7 @@
 	for (i = 0; i < NUM_BUCKETS; i++) {
 		list_for_each_entry (hc, _name_buckets + i, name_list) {
 			needed += sizeof(struct dm_name_list);
-			needed += strlen(hc->name);
+			needed += strlen(hc->name) + 1;
 			needed += ALIGN_MASK;
 		}
 	}
@@ -850,7 +850,6 @@
 	int r;
 	struct mapped_device *md;
 	struct dm_table *table;
-	DECLARE_WAITQUEUE(wq, current);
 
 	md = find_device(param);
 	if (!md)
@@ -859,12 +858,10 @@
 	/*
 	 * Wait for a notification event
 	 */
-	set_current_state(TASK_INTERRUPTIBLE);
-	if (!dm_add_wait_queue(md, &wq, param->event_nr)) {
-		schedule();
-		dm_remove_wait_queue(md, &wq);
+	if (dm_wait_event(md, param->event_nr)) {
+		r = -ERESTARTSYS;
+		goto out;
 	}
- 	set_current_state(TASK_RUNNING);
 
 	/*
 	 * The userland program is going to want to know what
--- diff/drivers/md/dm-table.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/dm-table.c	2004-05-27 18:34:16.000000000 +0100
@@ -181,8 +181,8 @@
 	/*
 	 * Allocate both the target array and offset array at once.
 	 */
-	n_highs = (sector_t *) dm_vcalloc(sizeof(struct dm_target) +
-					  sizeof(sector_t), num);
+	n_highs = (sector_t *) dm_vcalloc(num, sizeof(struct dm_target) +
+					  sizeof(sector_t));
 	if (!n_highs)
 		return -ENOMEM;
 
@@ -900,6 +900,28 @@
 	}
 }
 
+int dm_table_flush_all(struct dm_table *t)
+{
+	struct list_head *d, *devices = dm_table_get_devices(t);
+	int ret = 0;
+
+	for (d = devices->next; d != devices; d = d->next) {
+		struct dm_dev *dd = list_entry(d, struct dm_dev, list);
+		request_queue_t *q = bdev_get_queue(dd->bdev);
+		int err;
+
+		if (!q->issue_flush_fn)
+			err = -EOPNOTSUPP;
+		else
+			err = q->issue_flush_fn(q, dd->bdev->bd_disk, NULL);
+
+		if (!ret)
+			ret = err;
+	}
+
+	return ret;
+}
+
 EXPORT_SYMBOL(dm_vcalloc);
 EXPORT_SYMBOL(dm_get_device);
 EXPORT_SYMBOL(dm_put_device);
@@ -908,3 +930,4 @@
 EXPORT_SYMBOL(dm_table_put);
 EXPORT_SYMBOL(dm_table_get);
 EXPORT_SYMBOL(dm_table_unplug_all);
+EXPORT_SYMBOL(dm_table_flush_all);
--- diff/drivers/md/dm-target.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/dm-target.c	2004-05-27 18:34:16.000000000 +0100
@@ -7,6 +7,7 @@
 #include "dm.h"
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/bio.h>
 #include <linux/slab.h>
@@ -181,7 +182,7 @@
 	.map  = io_err_map,
 };
 
-int dm_target_init(void)
+int __init dm_target_init(void)
 {
 	return dm_register_target(&error_target);
 }
--- diff/drivers/md/dm.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/dm.c	2004-05-27 18:34:16.000000000 +0100
@@ -80,7 +80,7 @@
 	/*
 	 * Event handling.
 	 */
-	uint32_t event_nr;
+	atomic_t event_nr;
 	wait_queue_head_t eventq;
 
 	/*
@@ -93,7 +93,7 @@
 static kmem_cache_t *_io_cache;
 static kmem_cache_t *_tio_cache;
 
-static __init int local_init(void)
+static int __init local_init(void)
 {
 	int r;
 
@@ -369,6 +369,7 @@
 		struct dm_io *io = tio->io;
 		free_tio(tio->io->md, tio);
 		dec_pending(io, -EIO);
+		bio_put(clone);
 	}
 }
 
@@ -585,6 +586,21 @@
 	return 0;
 }
 
+static int dm_flush_all(request_queue_t *q, struct gendisk *disk,
+			sector_t *error_sector)
+{
+	struct mapped_device *md = q->queuedata;
+	struct dm_table *map = dm_get_table(md);
+	int ret = -ENXIO;
+
+	if (map) {
+		ret = dm_table_flush_all(md->map);
+		dm_table_put(map);
+	}
+
+	return ret;
+}
+
 static void dm_unplug_all(request_queue_t *q)
 {
 	struct mapped_device *md = q->queuedata;
@@ -662,6 +678,8 @@
 	return r;
 }
 
+static struct block_device_operations dm_blk_dops;
+
 /*
  * Allocate and initialise a blank device with a given minor.
  */
@@ -684,6 +702,7 @@
 	init_rwsem(&md->lock);
 	rwlock_init(&md->map_lock);
 	atomic_set(&md->holders, 1);
+	atomic_set(&md->event_nr, 0);
 
 	md->queue = blk_alloc_queue(GFP_KERNEL);
 	if (!md->queue)
@@ -694,6 +713,7 @@
 	md->queue->backing_dev_info.congested_data = md;
 	blk_queue_make_request(md->queue, dm_request);
 	md->queue->unplug_fn = dm_unplug_all;
+	md->queue->issue_flush_fn = dm_flush_all;
 
 	md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
 				     mempool_free_slab, _io_cache);
@@ -753,10 +773,8 @@
 {
 	struct mapped_device *md = (struct mapped_device *) context;
 
-	down_write(&md->lock);
-	md->event_nr++;
+	atomic_inc(&md->event_nr);;
 	wake_up(&md->eventq);
-	up_write(&md->lock);
 }
 
 static void __set_size(struct gendisk *disk, sector_t size)
@@ -1054,35 +1072,13 @@
  *---------------------------------------------------------------*/
 uint32_t dm_get_event_nr(struct mapped_device *md)
 {
-	uint32_t r;
-
-	down_read(&md->lock);
-	r = md->event_nr;
-	up_read(&md->lock);
-
-	return r;
+	return atomic_read(&md->event_nr);
 }
 
-int dm_add_wait_queue(struct mapped_device *md, wait_queue_t *wq,
-		      uint32_t event_nr)
+int dm_wait_event(struct mapped_device *md, int event_nr)
 {
-	down_write(&md->lock);
-	if (event_nr != md->event_nr) {
-		up_write(&md->lock);
-		return 1;
-	}
-
-	add_wait_queue(&md->eventq, wq);
-	up_write(&md->lock);
-
-	return 0;
-}
-
-void dm_remove_wait_queue(struct mapped_device *md, wait_queue_t *wq)
-{
-	down_write(&md->lock);
-	remove_wait_queue(&md->eventq, wq);
-	up_write(&md->lock);
+	return wait_event_interruptible(md->eventq,
+			(event_nr != atomic_read(&md->event_nr)));
 }
 
 /*
@@ -1099,7 +1095,7 @@
 	return test_bit(DMF_SUSPENDED, &md->flags);
 }
 
-struct block_device_operations dm_blk_dops = {
+static struct block_device_operations dm_blk_dops = {
 	.open = dm_blk_open,
 	.release = dm_blk_close,
 	.owner = THIS_MODULE
--- diff/drivers/md/dm.h	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/dm.h	2004-05-27 18:34:16.000000000 +0100
@@ -31,8 +31,6 @@
 
 #define SECTOR_SHIFT 9
 
-extern struct block_device_operations dm_blk_dops;
-
 /*
  * List of devices that a metadevice uses and should open/close.
  */
@@ -81,9 +79,7 @@
  * Event functions.
  */
 uint32_t dm_get_event_nr(struct mapped_device *md);
-int dm_add_wait_queue(struct mapped_device *md, wait_queue_t *wq,
-		      uint32_t event_nr);
-void dm_remove_wait_queue(struct mapped_device *md, wait_queue_t *wq);
+int dm_wait_event(struct mapped_device *md, int event_nr);
 
 /*
  * Info functions.
@@ -117,6 +113,7 @@
 void dm_table_resume_targets(struct dm_table *t);
 int dm_table_any_congested(struct dm_table *t, int bdi_bits);
 void dm_table_unplug_all(struct dm_table *t);
+int dm_table_flush_all(struct dm_table *t);
 
 /*-----------------------------------------------------------------
  * A registry of target types.
--- diff/drivers/md/linear.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/linear.c	2004-05-27 18:34:16.000000000 +0100
@@ -47,7 +47,6 @@
 		return hash->dev0;
 }
 
-
 /**
  *	linear_mergeable_bvec -- tell bio layer if a two requests can be merged
  *	@q: request queue
@@ -93,6 +92,27 @@
 	}
 }
 
+static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
+			      sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	linear_conf_t *conf = mddev_to_conf(mddev);
+	int i, ret = 0;
+
+	for (i=0; i < mddev->raid_disks; i++) {
+		struct block_device *bdev = conf->disks[i].rdev->bdev;
+		request_queue_t *r_queue = bdev_get_queue(bdev);
+
+		if (!r_queue->issue_flush_fn) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+		ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+		if (ret)
+			break;
+	}
+	return ret;
+}
 
 static int linear_run (mddev_t *mddev)
 {
@@ -200,6 +220,7 @@
 
 	blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
 	mddev->queue->unplug_fn = linear_unplug;
+	mddev->queue->issue_flush_fn = linear_issue_flush;
 	return 0;
 
 out:
--- diff/drivers/md/md.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/md.c	2004-05-27 18:34:16.000000000 +0100
@@ -154,6 +154,39 @@
 		tmp = tmp->next;})					\
 		)
 
+int md_flush_mddev(mddev_t *mddev, sector_t *error_sector)
+{
+	struct list_head *tmp;
+	mdk_rdev_t *rdev;
+	int ret = 0;
+
+	/*
+	 * this list iteration is done without any locking in md?!
+	 */
+	ITERATE_RDEV(mddev, rdev, tmp) {
+		request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+		int err;
+
+		if (!r_queue->unplug_fn)
+			err = -EOPNOTSUPP;
+		else
+			err = r_queue->issue_flush_fn(r_queue, rdev->bdev->bd_disk, error_sector);
+
+		if (!ret)
+			ret = err;
+	}
+
+	return ret;
+}
+
+static int md_flush_all(request_queue_t *q, struct gendisk *disk,
+			 sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+
+	return md_flush_mddev(mddev, error_sector);
+}
+
 static int md_fail_request (request_queue_t *q, struct bio *bio)
 {
 	bio_io_error(bio, bio->bi_size);
@@ -1645,6 +1678,7 @@
 	 */
 	mddev->queue->queuedata = mddev;
 	mddev->queue->make_request_fn = mddev->pers->make_request;
+	mddev->queue->issue_flush_fn = md_flush_all;
 
 	mddev->changed = 1;
 	return 0;
--- diff/drivers/md/multipath.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/md/multipath.c	2004-05-27 18:34:17.000000000 +0100
@@ -236,6 +236,31 @@
 	seq_printf (seq, "]");
 }
 
+static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
+				 sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	multipath_conf_t *conf = mddev_to_conf(mddev);
+	int i, ret = 0;
+
+	for (i=0; i<mddev->raid_disks; i++) {
+		mdk_rdev_t *rdev = conf->multipaths[i].rdev;
+		if (rdev && !rdev->faulty) {
+			struct block_device *bdev = rdev->bdev;
+			request_queue_t *r_queue = bdev_get_queue(bdev);
+
+			if (!r_queue->issue_flush_fn) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+
+			ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+			if (ret)
+				break;
+		}
+	}
+	return ret;
+}
 
 /*
  * Careful, this can execute in IRQ contexts as well!
@@ -451,6 +476,8 @@
 
 	mddev->queue->unplug_fn = multipath_unplug;
 
+	mddev->queue->issue_flush_fn = multipath_issue_flush;
+
 	conf->working_disks = 0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		disk_idx = rdev->raid_disk;
--- diff/drivers/md/raid0.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/raid0.c	2004-05-27 18:34:17.000000000 +0100
@@ -40,6 +40,31 @@
 	}
 }
 
+static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk,
+			     sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	raid0_conf_t *conf = mddev_to_conf(mddev);
+	mdk_rdev_t **devlist = conf->strip_zone[0].dev;
+	int i, ret = 0;
+
+	for (i=0; i<mddev->raid_disks; i++) {
+		struct block_device *bdev = devlist[i]->bdev;
+		request_queue_t *r_queue = bdev_get_queue(bdev);
+
+		if (!r_queue->issue_flush_fn) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		ret =r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+
 static int create_strip_zones (mddev_t *mddev)
 {
 	int i, c, j;
@@ -219,6 +244,8 @@
 
 	mddev->queue->unplug_fn = raid0_unplug;
 
+	mddev->queue->issue_flush_fn = raid0_issue_flush;
+
 	printk("raid0: done.\n");
 	return 0;
  abort:
--- diff/drivers/md/raid1.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/md/raid1.c	2004-05-27 18:34:17.000000000 +0100
@@ -479,6 +479,32 @@
 	unplug_slaves(q->queuedata);
 }
 
+static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
+			     sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	conf_t *conf = mddev_to_conf(mddev);
+	unsigned long flags;
+	int i, ret = 0;
+
+	spin_lock_irqsave(&conf->device_lock, flags);
+	for (i=0; i<mddev->raid_disks; i++) {
+		mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+		if (rdev && !rdev->faulty) {
+			struct block_device *bdev = rdev->bdev;
+			request_queue_t *r_queue = bdev_get_queue(bdev);
+
+			if (r_queue->issue_flush_fn) {
+				ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+				if (ret)
+					break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&conf->device_lock, flags);
+	return ret;
+}
+
 /*
  * Throttle resync depth, so that we can both get proper overlapping of
  * requests, but are still able to handle normal requests quickly.
@@ -1147,6 +1173,7 @@
 	}
 	mddev->queue->unplug_fn = raid1_unplug;
 
+	mddev->queue->issue_flush_fn = raid1_issue_flush;
 
 	ITERATE_RDEV(mddev, rdev, tmp) {
 		disk_idx = rdev->raid_disk;
--- diff/drivers/md/raid5.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/md/raid5.c	2004-05-27 18:34:17.000000000 +0100
@@ -1339,6 +1339,39 @@
 	unplug_slaves(mddev);
 }
 
+static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
+			     sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	raid5_conf_t *conf = mddev_to_conf(mddev);
+	int i, ret = 0;
+
+	for (i=0; i<mddev->raid_disks; i++) {
+		mdk_rdev_t *rdev = conf->disks[i].rdev;
+		if (rdev && !rdev->faulty) {
+			struct block_device *bdev = rdev->bdev;
+			request_queue_t *r_queue;
+
+			if (!bdev)
+				continue;
+
+			r_queue = bdev_get_queue(bdev);
+			if (!r_queue)
+				continue;
+
+			if (!r_queue->issue_flush_fn) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+
+			ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+			if (ret)
+				break;
+		}
+	}
+	return ret;
+}
+
 static inline void raid5_plug_device(raid5_conf_t *conf)
 {
 	spin_lock_irq(&conf->device_lock);
@@ -1545,6 +1578,7 @@
 	atomic_set(&conf->preread_active_stripes, 0);
 
 	mddev->queue->unplug_fn = raid5_unplug_device;
+	mddev->queue->issue_flush_fn = raid5_issue_flush;
 
 	PRINTK("raid5: run(%s) called.\n", mdname(mddev));
 
--- diff/drivers/md/raid6main.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/md/raid6main.c	2004-05-27 18:34:17.000000000 +0100
@@ -1501,6 +1501,39 @@
 	unplug_slaves(mddev);
 }
 
+static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
+			     sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	raid6_conf_t *conf = mddev_to_conf(mddev);
+	int i, ret = 0;
+
+	for (i=0; i<mddev->raid_disks; i++) {
+		mdk_rdev_t *rdev = conf->disks[i].rdev;
+		if (rdev && !rdev->faulty) {
+			struct block_device *bdev = rdev->bdev;
+			request_queue_t *r_queue;
+
+			if (!bdev)
+				continue;
+
+			r_queue = bdev_get_queue(bdev);
+			if (!r_queue)
+				continue;
+
+			if (!r_queue->issue_flush_fn) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+
+			ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+			if (ret)
+				break;
+		}
+	}
+	return ret;
+}
+
 static inline void raid6_plug_device(raid6_conf_t *conf)
 {
 	spin_lock_irq(&conf->device_lock);
@@ -1708,6 +1741,7 @@
 	atomic_set(&conf->preread_active_stripes, 0);
 
 	mddev->queue->unplug_fn = raid6_unplug_device;
+	mddev->queue->issue_flush_fn = raid6_issue_flush;
 
 	PRINTK("raid6: run(%s) called.\n", mdname(mddev));
 
--- diff/drivers/media/video/ir-kbd-gpio.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/media/video/ir-kbd-gpio.c	2004-05-27 18:34:17.000000000 +0100
@@ -64,7 +64,7 @@
 	[ 13 ] = KEY_STOP,        // freeze 
 	[ 29 ] = KEY_RECORD,      // capture 
 	[  3 ] = KEY_PLAY,        // unmarked
-	[ 24 ] = KEY_RED,         // unmarked
+	[ 23 ] = KEY_RED,         // unmarked
 	[  7 ] = KEY_GREEN,       // unmarked
 
 #if 0
--- diff/drivers/media/video/mxb.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/media/video/mxb.c	2004-05-27 18:34:17.000000000 +0100
@@ -24,42 +24,15 @@
 #define DEBUG_VARIABLE debug
 
 #include <media/saa7146_vv.h>
-#include <linux/video_decoder.h>	/* for saa7111a */
+#include <media/tuner.h>
+#include <linux/video_decoder.h>
 
 #include "mxb.h"
 #include "tea6415c.h"
 #include "tea6420.h"
 #include "tda9840.h"
-#include <media/tuner.h>
 
-#define I2C_SAA7111A            0x24
-
-/* All unused bytes are reserverd. */
-#define SAA711X_CHIP_VERSION            0x00
-#define SAA711X_ANALOG_INPUT_CONTROL_1  0x02
-#define SAA711X_ANALOG_INPUT_CONTROL_2  0x03
-#define SAA711X_ANALOG_INPUT_CONTROL_3  0x04
-#define SAA711X_ANALOG_INPUT_CONTROL_4  0x05
-#define SAA711X_HORIZONTAL_SYNC_START   0x06
-#define SAA711X_HORIZONTAL_SYNC_STOP    0x07
-#define SAA711X_SYNC_CONTROL            0x08
-#define SAA711X_LUMINANCE_CONTROL       0x09
-#define SAA711X_LUMINANCE_BRIGHTNESS    0x0A
-#define SAA711X_LUMINANCE_CONTRAST      0x0B
-#define SAA711X_CHROMA_SATURATION       0x0C
-#define SAA711X_CHROMA_HUE_CONTROL      0x0D
-#define SAA711X_CHROMA_CONTROL          0x0E
-#define SAA711X_FORMAT_DELAY_CONTROL    0x10
-#define SAA711X_OUTPUT_CONTROL_1        0x11
-#define SAA711X_OUTPUT_CONTROL_2        0x12
-#define SAA711X_OUTPUT_CONTROL_3        0x13
-#define SAA711X_V_GATE_1_START          0x15
-#define SAA711X_V_GATE_1_STOP           0x16
-#define SAA711X_V_GATE_1_MSB            0x17
-#define SAA711X_TEXT_SLICER_STATUS      0x1A
-#define SAA711X_DECODED_BYTES_OF_TS_1   0x1B
-#define SAA711X_DECODED_BYTES_OF_TS_2   0x1C
-#define SAA711X_STATUS_BYTE             0x1F
+#define I2C_SAA7111 0x24
 
 #define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0) 
 
@@ -175,42 +148,33 @@
 
 static struct saa7146_extension extension;
 
-static int mxb_vbi_bypass(struct saa7146_dev* dev)
-{
-	struct mxb* mxb = (struct mxb*)dev->ext_priv;
-	s32 byte = 0x0;
-	int result = 0;
-
-	DEB_EE(("dev:%p\n",dev));
-
-	/* switch bypass in saa7111a, this should be done in the
-	   saa7111a driver of course... */
-	if ( -1 == (result = i2c_smbus_read_byte_data(mxb->saa7111a, SAA711X_OUTPUT_CONTROL_3))) {
-		DEB_D(("could not read from saa7111a.\n"));
-		return -EFAULT;
-	}
-	byte = result;
-	byte &= 0xf0;
-	byte |= 0x0a;
-
-	if ( 0 != (result = i2c_smbus_write_byte_data(mxb->saa7111a, SAA711X_OUTPUT_CONTROL_3, byte))) {
-		DEB_D(("could not write to saa7111a.\n"));
-		return -EFAULT;
-	}
-	return 0;
-}
-
 static int mxb_probe(struct saa7146_dev* dev)
 {
 	struct mxb* mxb = 0;
 	struct i2c_client *client;
 	struct list_head *item;
+	int result;
 
-	request_module("tuner");
-	request_module("tea6420");
-	request_module("tea6415c");
-	request_module("tda9840");
-	request_module("saa7111");
+	if ((result = request_module("saa7111")) < 0) {
+		printk("mxb: saa7111 i2c module not available.\n");
+		return -ENODEV;
+	}
+	if ((result = request_module("tuner")) < 0) {
+		printk("mxb: tuner i2c module not available.\n");
+		return -ENODEV;
+	}
+	if ((result = request_module("tea6420")) < 0) {
+		printk("mxb: tea6420 i2c module not available.\n");
+		return -ENODEV;
+	}
+	if ((result = request_module("tea6415c")) < 0) {
+		printk("mxb: tea6415c i2c module not available.\n");
+		return -ENODEV;
+	}
+	if ((result = request_module("tda9840")) < 0) {
+		printk("mxb: tda9840 i2c module not available.\n");
+		return -ENODEV;
+	}
 
 	mxb = (struct mxb*)kmalloc(sizeof(struct mxb), GFP_KERNEL);
 	if( NULL == mxb ) {
@@ -219,10 +183,6 @@
 	}
 	memset(mxb, 0x0, sizeof(struct mxb));	
 
-	/* FIXME: enable i2c-port pins, video-port-pins
-	   video port pins should be enabled here ?! */
-	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
-
 	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, I2C_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
 	if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
@@ -241,7 +201,7 @@
 			mxb->tea6415c = client;
 		if( I2C_TDA9840 == client->addr ) 
 			mxb->tda9840 = client;
-		if( I2C_SAA7111A == client->addr ) 
+		if( I2C_SAA7111 == client->addr )
 			mxb->saa7111a = client;
 		if( 0x60 == client->addr ) 
 			mxb->tuner = client;
@@ -251,8 +211,7 @@
 	if(    0 == mxb->tea6420_1	|| 0 == mxb->tea6420_2	|| 0 == mxb->tea6415c
 	    || 0 == mxb->tda9840	|| 0 == mxb->saa7111a	|| 0 == mxb->tuner ) {
 
-		printk("mxb: did not find all i2c devices. are you sure you\n");
-		printk("mxb: insmod'ed tea6420, tea6415c, saa7111, tea6415c and tuner?\n");
+		printk("mxb: did not find all i2c devices. aborting\n");
 		i2c_del_adapter(&mxb->i2c_adapter);
 		kfree(mxb);
 		return -ENODEV;
@@ -322,37 +281,35 @@
 	{-1, { 0} }
 };
 
-static unsigned char mxb_saa7111_init[25] = {
-	0x00,
-	
-	0x00,	  /* 00 - ID byte */
-	0x00,	  /* 01 - reserved */
+static const unsigned char mxb_saa7111_init[] = {
+	0x00, 0x00,	  /* 00 - ID byte */
+	0x01, 0x00,	  /* 01 - reserved */
 
 	/*front end */
-	0xd8,	  /* 02 - FUSE=x, GUDL=x, MODE=x */
-	0x23,	  /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
-	0x00,	  /* 04 - GAI1=256 */
-	0x00,	  /* 05 - GAI2=256 */
+	0x02, 0xd8,	  /* 02 - FUSE=x, GUDL=x, MODE=x */
+	0x03, 0x23,	  /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
+	0x04, 0x00,	  /* 04 - GAI1=256 */
+	0x05, 0x00,	  /* 05 - GAI2=256 */
 
 	/* decoder */
-	0xf0,	  /* 06 - HSB at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
-	0x30,	  /* 07 - HSS at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
-	0xa8,	  /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
-	0x02,	  /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
-	0x80,	  /* 0a - BRIG=128 */
-	0x47,	  /* 0b - CONT=1.109 */
-	0x40,	  /* 0c - SATN=1.0 */
-	0x00,	  /* 0d - HUE=0 */
-	0x01,	  /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
-	0x00,	  /* 0f - reserved */
-	0xd0,	  /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
-	0x8c,	  /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
-	0x80,	  /* 12 - xx output control 2 */
-	0x30,	  /* 13 - xx output control 3 */
-	0x00,	  /* 14 - reserved */
-	0x15,	  /* 15 - VBI */
-	0x04,	  /* 16 - VBI */
-	0x00,	  /* 17 - VBI */
+	0x06, 0xf0,	  /* 06 - HSB at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
+	0x07, 0x30,	  /* 07 - HSS at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
+	0x08, 0xa8,	  /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
+	0x09, 0x02,	  /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
+	0x0a, 0x80,	  /* 0a - BRIG=128 */
+	0x0b, 0x47,	  /* 0b - CONT=1.109 */
+	0x0c, 0x40,	  /* 0c - SATN=1.0 */
+	0x0d, 0x00,	  /* 0d - HUE=0 */
+	0x0e, 0x01,	  /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
+	0x0f, 0x00,	  /* 0f - reserved */
+	0x10, 0xd0,	  /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
+	0x11, 0x8c,	  /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
+	0x12, 0x80,	  /* 12 - xx output control 2 */
+	0x13, 0x30,	  /* 13 - xx output control 3 */
+	0x14, 0x00,	  /* 14 - reserved */
+	0x15, 0x15,	  /* 15 - VBI */
+	0x16, 0x04,	  /* 16 - VBI */
+	0x17, 0x00,	  /* 17 - VBI */
 };
 
 /* bring hardware to a sane state. this has to be done, just in case someone
@@ -362,25 +319,29 @@
 static int mxb_init_done(struct saa7146_dev* dev)
 {
 	struct mxb* mxb = (struct mxb*)dev->ext_priv;
-	
+	struct video_decoder_init init;
 	struct i2c_msg msg;
 
 	int i = 0, err = 0;
 	struct	tea6415c_multiplex vm;	
 
+	/* select video mode in saa7111a */
+	i = VIDEO_MODE_PAL;
+	/* fixme: currently pointless: gets overwritten by configuration below */
+	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
+
 	/* write configuration to saa7111a */
-	i = i2c_master_send(mxb->saa7111a, mxb_saa7111_init, sizeof(mxb_saa7111_init));
-	if (i < 0) {
-		printk("failed to initialize saa7111a. this should never happen.\n");
-	}
+	init.data = mxb_saa7111_init;
+	init.len = sizeof(mxb_saa7111_init);
+	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
 
 	/* select tuner-output on saa7111a */
 	i = 0;
 	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
-//	i = VIDEO_MODE_PAL;
-//	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
 
-	mxb_vbi_bypass(dev);
+	/* enable vbi bypass */
+	i = 1;
+	mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
 
 	/* select a tuner type */
 	i = 5; 
@@ -538,36 +499,6 @@
 	return 0;
 }
 
-/* hack: this should go into saa711x */
-static int saa7111_set_gpio(struct saa7146_dev *dev, int bl)
-{
-	struct mxb* mxb = (struct mxb*)dev->ext_priv;
-	s32 byte = 0x0;
-	int result = 0;
-	
-	DEB_EE(("dev:%p\n",dev));
-
-	/* get the old register contents */
-	if ( -1 == (byte = i2c_smbus_read_byte_data(mxb->saa7111a, SAA711X_OUTPUT_CONTROL_1))) {
-		DEB_D(("could not read from saa711x\n"));
-		return -EFAULT;
-	}
-	
-	if( 0 == bl ) {
-		byte &= 0x7f;
-	} else {
-		byte |= 0x80;
-	}
-
-	/* write register contents back */
-	if ( 0 != (result = i2c_smbus_write_byte_data(mxb->saa7111a, SAA711X_OUTPUT_CONTROL_1, byte))) {
-		DEB_D(("could not write to saa711x\n"));
-		return -EFAULT;
-	}
-
-	return 0;
-}
-
 static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) 
 {
 	struct saa7146_dev *dev = fh->dev;
@@ -988,18 +919,22 @@
 
 static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
 {
+	struct mxb* mxb = (struct mxb*)dev->ext_priv;
+	int zero = 0;
+	int one = 1;
+
 	if(V4L2_STD_PAL_I == std->id ) {
 		DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
 		/* set the 7146 gpio register -- I don't know what this does exactly */
       		saa7146_write(dev, GPIO_CTRL, 0x00404050);
 		/* unset the 7111 gpio register -- I don't know what this does exactly */
-		saa7111_set_gpio(dev,0);
+		mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
 	} else {
 		DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
 		/* set the 7146 gpio register -- I don't know what this does exactly */
       		saa7146_write(dev, GPIO_CTRL, 0x00404050);
 		/* set the 7111 gpio register -- I don't know what this does exactly */
-		saa7111_set_gpio(dev,1);
+		mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
 	}
 	return 0;
 }
--- diff/drivers/mtd/chips/sharp.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/mtd/chips/sharp.c	2004-05-27 18:34:17.000000000 +0100
@@ -30,6 +30,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/cfi.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #define CMD_RESET		0xffffffff
 #define CMD_READ_ID		0x90909090
--- diff/drivers/mtd/maps/uclinux.c	2004-05-19 22:11:52.000000000 +0100
+++ source/drivers/mtd/maps/uclinux.c	2004-05-27 18:34:17.000000000 +0100
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/major.h>
+#include <linux/root_dev.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
--- diff/drivers/net/3c509.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/3c509.c	2004-05-27 18:34:17.000000000 +0100
@@ -56,10 +56,6 @@
 		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"
@@ -265,7 +261,7 @@
 };
 #endif /* CONFIG_MCA */
 
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
@@ -362,7 +358,7 @@
 	if (lp->pmdev)
 		pm_unregister(lp->pmdev);
 #endif
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	if (lp->type == EL3_PNP)
 		pnp_device_detach(to_pnp_dev(lp->dev));
 #endif
@@ -381,7 +377,7 @@
 	u16 phys_addr[3];
 	static int current_tag;
 	int err = -ENODEV;
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	static int pnp_cards;
 	struct pnp_dev *idev = NULL;
 
@@ -436,9 +432,6 @@
 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 (!request_region(id_port, 1, "3c509"))
@@ -456,7 +449,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
@@ -487,7 +480,7 @@
 		phys_addr[i] = htons(id_read_eeprom(i));
 	}
 
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	if (nopnp == 0) {
 		/* The ISA PnP 3c509 cards respond to the ID sequence.
 		   This check is needed in order not to register them twice. */
@@ -512,19 +505,9 @@
 	{
 		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
 
 	dev = alloc_etherdev(sizeof (struct el3_private));
 	if (!dev)
@@ -555,11 +538,7 @@
 	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)
@@ -568,7 +547,7 @@
 	/* Free the interrupt so that some other card can use it. */
 	outw(0x0f00, ioaddr + WN0_IRQ);
 
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
  found:							/* PNP jumps here... */
 #endif /* __ISAPNP__ */
 
@@ -577,7 +556,7 @@
 	dev->irq = irq;
 	dev->if_port = if_port;
 	lp = netdev_priv(dev);
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	lp->dev = &idev->dev;
 #endif
 	err = el3_common_init(dev);
@@ -601,7 +580,7 @@
 	return 0;
 
 out1:
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	if (idev)
 		pnp_device_detach(idev);
 #endif
@@ -1461,12 +1440,6 @@
 	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. */
@@ -1629,7 +1602,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");
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 MODULE_PARM(nopnp, "i");
 MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
 MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
--- diff/drivers/net/82596.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/82596.c	2004-05-27 18:34:17.000000000 +0100
@@ -58,7 +58,6 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 
 static char version[] __initdata =
 	"82596.c $Revision: 1.5 $\n";
--- diff/drivers/net/8390.h	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/net/8390.h	2004-05-27 18:34:17.000000000 +0100
@@ -143,7 +143,7 @@
 #define inb_p(_p)	inb(_p)
 #define outb_p(_v,_p)	outb(_v,_p)
 
-#elif defined(CONFIG_NET_CBUS) || defined(CONFIG_NE_H8300)
+#elif defined(CONFIG_NET_CBUS) || defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE)
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 #else
 #define EI_SHIFT(x)	(x)
--- diff/drivers/net/Kconfig	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/net/Kconfig	2004-05-27 18:34:17.000000000 +0100
@@ -922,7 +922,7 @@
 
 config NET_ISA
 	bool "Other ISA cards"
-	depends on NET_ETHERNET && ISA && !X86_PC9800
+	depends on NET_ETHERNET && ISA
 	---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
@@ -1105,56 +1105,6 @@
 	  the Ethernet-HOWTO, available from
 	  <http://www.tldp.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
-	select CRC32
-
-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 && BROKEN
@@ -1829,7 +1779,7 @@
 	  controller on the Motorola ColdFire 5272 processor.
 
 config NE_H8300
-	bool "NE2000 compatible support for H8/300"
+	tristate "NE2000 compatible support for H8/300"
 	depends on H8300 && NET_ETHERNET
 	help
 	  Say Y here if you want to use the NE2000 compatible
@@ -1987,6 +1937,11 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called r8169.  This is recommended.
 
+config R8169_NAPI
+	bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
+	depends on R8169 && EXPERIMENTAL 
+
+
 config SK98LIN
 	tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
 	depends on PCI
--- diff/drivers/net/Makefile	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/net/Makefile	2004-05-27 18:34:17.000000000 +0100
@@ -78,7 +78,6 @@
 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
@@ -187,4 +186,6 @@
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
 
+# Must come after all NICs that might use them
 obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_KGDB) += kgdb_eth.o
--- diff/drivers/net/Space.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/net/Space.c	2004-05-27 18:34:17.000000000 +0100
@@ -191,8 +191,8 @@
 #ifdef CONFIG_E2100		/* Cabletron E21xx series. */
 	{e2100_probe, 0},
 #endif
-#if defined(CONFIG_NE2000) || defined(CONFIG_NE2K_CBUS)	|| \
-    defined(CONFIG_NE_H8300)  /* ISA & PC-9800 CBUS (use ne2k-pci for PCI cards) */
+#if defined(CONFIG_NE2000) || \
+    defined(CONFIG_NE_H8300)  /* ISA (use ne2k-pci for PCI cards) */
 	{ne_probe, 0},
 #endif
 #ifdef CONFIG_LANCE		/* ISA/VLB (use pcnet32 for PCI cards) */
--- diff/drivers/net/acenic.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/acenic.c	2004-05-27 18:34:17.000000000 +0100
@@ -131,7 +131,6 @@
 #define PCI_DEVICE_ID_SGI_ACENIC	0x0009
 #endif
 
-#if LINUX_VERSION_CODE >= 0x20400
 static struct pci_device_id acenic_pci_tbl[] = {
 	{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
@@ -156,37 +155,6 @@
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
-#endif
-
-
-#ifndef MODULE_LICENSE
-#define MODULE_LICENSE(a)
-#endif
-
-#ifndef wmb
-#define wmb()	mb()
-#endif
-
-#ifndef __exit
-#define __exit
-#endif
-
-#ifndef __devinit
-#define __devinit	__init
-#endif
-
-#ifndef SMP_CACHE_BYTES
-#define SMP_CACHE_BYTES	L1_CACHE_BYTES
-#endif
-
-#ifndef SET_MODULE_OWNER
-#define SET_MODULE_OWNER(dev)		do{} while(0)
-#define ACE_MOD_INC_USE_COUNT		MOD_INC_USE_COUNT
-#define ACE_MOD_DEC_USE_COUNT		MOD_DEC_USE_COUNT
-#else
-#define ACE_MOD_INC_USE_COUNT		do{} while(0)
-#define ACE_MOD_DEC_USE_COUNT		do{} while(0)
-#endif
 
 #ifndef SET_NETDEV_DEV
 #define SET_NETDEV_DEV(net, pdev)	do{} while(0)
@@ -198,151 +166,8 @@
 #define ace_sync_irq(irq)	synchronize_irq()
 #endif
 
-#if LINUX_VERSION_CODE < 0x2051e
-#define local_irq_save(flags)		do{__save_flags(flags) ; \
-					   __cli();} while(0)
-#define local_irq_restore(flags)	__restore_flags(flags)
-#endif
-
-#if (LINUX_VERSION_CODE < 0x02030d)
-#define pci_resource_start(dev, bar)	dev->base_address[bar]
-#elif (LINUX_VERSION_CODE < 0x02032c)
-#define pci_resource_start(dev, bar)	dev->resource[bar].start
-#endif
-
-#if (LINUX_VERSION_CODE < 0x02030e)
-#define net_device device
-#endif
-
-
-#if (LINUX_VERSION_CODE < 0x02032a)
-typedef u32 dma_addr_t;
-
-static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-					 dma_addr_t *dma_handle)
-{
-	void *virt_ptr;
-
-	virt_ptr = kmalloc(size, GFP_KERNEL);
-	if (!virt_ptr)
-		return NULL;
-	*dma_handle = virt_to_bus(virt_ptr);
-	return virt_ptr;
-}
-
-#define pci_free_consistent(cookie, size, ptr, dma_ptr)	kfree(ptr)
-#define pci_map_page(cookie, page, off, size, dir)	\
-	virt_to_bus(page_address(page)+(off))
-#define pci_unmap_page(cookie, address, size, dir)
-#define pci_set_dma_mask(dev, mask)		\
-	(((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO)
-#define pci_dma_supported(dev, mask)		\
-	(((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0)
-
-#elif (LINUX_VERSION_CODE < 0x02040d)
-
-/*
- * 2.4.13 introduced pci_map_page()/pci_unmap_page() - for 2.4.12 and prior,
- * fall back on pci_map_single()/pci_unnmap_single().
- *
- * We are guaranteed that the page is mapped at this point since
- * pci_map_page() is only used upon valid struct skb's.
- */
-static inline dma_addr_t
-pci_map_page(struct pci_dev *cookie, struct page *page, unsigned long off,
-	     size_t size, int dir)
-{
-	void *page_virt;
-
-	page_virt = page_address(page);
-	if (!page_virt)
-		BUG();
-	return pci_map_single(cookie, (page_virt + off), size, dir);
-}
-#define pci_unmap_page(cookie, dma_addr, size, dir)	\
-	pci_unmap_single(cookie, dma_addr, size, dir)
-#endif
-
-#if (LINUX_VERSION_CODE < 0x020412)
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)		0
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do{} while(0)
-#define pci_unmap_len(PTR, LEN_NAME)		0
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do{} while(0)
-#endif
-
-
-#if (LINUX_VERSION_CODE < 0x02032b)
-/*
- * SoftNet
- *
- * For pre-softnet kernels we need to tell the upper layer not to
- * re-enter start_xmit() while we are in there. However softnet
- * guarantees not to enter while we are in there so there is no need
- * to do the netif_stop_queue() dance unless the transmit queue really
- * gets stuck. This should also improve performance according to tests
- * done by Aman Singla.
- */
-#define dev_kfree_skb_irq(a)			dev_kfree_skb(a)
-#define netif_wake_queue(dev)			clear_bit(0, &dev->tbusy)
-#define netif_stop_queue(dev)			set_bit(0, &dev->tbusy)
-#define late_stop_netif_stop_queue(dev)		do{} while(0)
-#define early_stop_netif_stop_queue(dev)	test_and_set_bit(0,&dev->tbusy)
-#define early_stop_netif_wake_queue(dev)	netif_wake_queue(dev)
-
-static inline void netif_start_queue(struct net_device *dev)
-{
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-}
-
-#define ace_mark_net_bh()			mark_bh(NET_BH)
-#define netif_queue_stopped(dev)		dev->tbusy
-#define netif_running(dev)			dev->start
-#define ace_if_down(dev)			do{dev->start = 0;} while(0)
-
-#define tasklet_struct				tq_struct
-static inline void tasklet_schedule(struct tasklet_struct *tasklet)
-{
-	queue_task(tasklet, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static inline void tasklet_init(struct tasklet_struct *tasklet,
-				void (*func)(unsigned long),
-				unsigned long data)
-{
-	tasklet->next = NULL;
-	tasklet->sync = 0;
-	tasklet->routine = (void (*)(void *))func;
-	tasklet->data = (void *)data;
-}
-#define tasklet_kill(tasklet)			do{} while(0)
-#else
-#define late_stop_netif_stop_queue(dev)		netif_stop_queue(dev)
-#define early_stop_netif_stop_queue(dev)	0
-#define early_stop_netif_wake_queue(dev)	do{} while(0)
-#define ace_mark_net_bh()			do{} while(0)
-#define ace_if_down(dev)			do{} while(0)
-#endif
-
-#if (LINUX_VERSION_CODE >= 0x02031b)
-#define NEW_NETINIT
-#define ACE_PROBE_ARG				void
-#else
-#define ACE_PROBE_ARG				struct net_device *dev
-#endif
-
-#ifndef min_t
-#define min_t(type,a,b)	(((a)<(b))?(a):(b))
-#endif
-
-#ifndef ARCH_HAS_PREFETCHW
-#ifndef prefetchw
-#define prefetchw(x)				do{} while(0)
-#endif
+#ifndef offset_in_page
+#define offset_in_page(ptr)	((unsigned long)(ptr) & ~PAGE_MASK)
 #endif
 
 #define ACE_MAX_MOD_PARMS	8
@@ -595,407 +420,323 @@
 static int tx_ratio[ACE_MAX_MOD_PARMS];
 static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
+MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
+MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(tx_ratio, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state");
+MODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level");
+MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives");
+MODULE_PARM_DESC(max_tx_desc, "AceNIC/3C985/GA620 max number of transmit descriptors to wait");
+MODULE_PARM_DESC(rx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first rx descriptor arrives");
+MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descriptors to wait");
+MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)");
+
+
 static char version[] __initdata = 
   "acenic.c: v0.92 08/05/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
-static struct net_device *root_dev;
-
-static int probed __initdata = 0;
-
-
-int __devinit acenic_probe (ACE_PROBE_ARG)
+static int __devinit acenic_probe_one(struct pci_dev *pdev,
+		const struct pci_device_id *id)
 {
-#ifdef NEW_NETINIT
 	struct net_device *dev;
-#endif
 	struct ace_private *ap;
-	struct pci_dev *pdev = NULL;
-	int boards_found = 0;
-	int version_disp;
-
-	if (probed)
-		return -ENODEV;
-	probed++;
-
-	version_disp = 0;
-
-	while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
-
-		if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
-		      ((pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE) ||
-		       (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_COPPER)))&&
-		    !((pdev->vendor == PCI_VENDOR_ID_3COM) &&
-		      (pdev->device == PCI_DEVICE_ID_3COM_3C985)) &&
-		    !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) &&
-		      ((pdev->device == PCI_DEVICE_ID_NETGEAR_GA620) || 
-		       (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620T))) &&
-		/*
-		 * Farallon used the DEC vendor ID on their cards by
-		 * mistake for a while
-		 */
-		    !((pdev->vendor == PCI_VENDOR_ID_DEC) &&
-		      (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) &&
-		    !((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
-		      (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T)) &&
-		    !((pdev->vendor == PCI_VENDOR_ID_SGI) &&
-		      (pdev->device == PCI_DEVICE_ID_SGI_ACENIC)))
-			continue;
-
-		dev = alloc_etherdev(sizeof(struct ace_private));
-		if (dev == NULL) {
-			printk(KERN_ERR "acenic: Unable to allocate "
-			       "net_device structure!\n");
-			break;
-		}
+	static int boards_found;
 
-		SET_MODULE_OWNER(dev);
-		SET_NETDEV_DEV(dev, &pdev->dev);
+	dev = alloc_etherdev(sizeof(struct ace_private));
+	if (dev == NULL) {
+		printk(KERN_ERR "acenic: Unable to allocate "
+		       "net_device structure!\n");
+		return -ENOMEM;
+	}
 
-		ap = dev->priv;
-		ap->pdev = pdev;
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
-		dev->open = &ace_open;
-		dev->hard_start_xmit = &ace_start_xmit;
-		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+	ap = dev->priv;
+	ap->pdev = pdev;
+
+	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 #if ACENIC_DO_VLAN
-		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-		dev->vlan_rx_register = ace_vlan_rx_register;
-		dev->vlan_rx_kill_vid = ace_vlan_rx_kill_vid;
-#endif
-		if (1) {
-			static void ace_watchdog(struct net_device *dev);
-			dev->tx_timeout = &ace_watchdog;
-			dev->watchdog_timeo = 5*HZ;
-		}
-		dev->stop = &ace_close;
-		dev->get_stats = &ace_get_stats;
-		dev->set_multicast_list = &ace_set_multicast_list;
-		dev->do_ioctl = &ace_ioctl;
-		dev->set_mac_address = &ace_set_mac_addr;
-		dev->change_mtu = &ace_change_mtu;
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	dev->vlan_rx_register = ace_vlan_rx_register;
+	dev->vlan_rx_kill_vid = ace_vlan_rx_kill_vid;
+#endif
+	if (1) {
+		static void ace_watchdog(struct net_device *dev);
+		dev->tx_timeout = &ace_watchdog;
+		dev->watchdog_timeo = 5*HZ;
+	}
 
-		/* display version info if adapter is found */
-		if (!version_disp)
-		{
-			/* set display flag to TRUE so that */
-			/* we only display this string ONCE */
-			version_disp = 1;
-			printk(version);
-		}
+	dev->open = &ace_open;
+	dev->stop = &ace_close;
+	dev->hard_start_xmit = &ace_start_xmit;
+	dev->get_stats = &ace_get_stats;
+	dev->set_multicast_list = &ace_set_multicast_list;
+	dev->do_ioctl = &ace_ioctl;
+	dev->set_mac_address = &ace_set_mac_addr;
+	dev->change_mtu = &ace_change_mtu;
 
-		if (pci_enable_device(pdev)) {
-			free_netdev(dev);
-			continue;
-		}
+	/* we only display this string ONCE */
+	if (!boards_found)
+		printk(version);
 
-		/*
-		 * Enable master mode before we start playing with the
-		 * pci_command word since pci_set_master() will modify
-		 * it.
-		 */
-		pci_set_master(pdev);
+	if (pci_enable_device(pdev))
+		goto fail_free_netdev;
 
-		pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
+	/*
+	 * Enable master mode before we start playing with the
+	 * pci_command word since pci_set_master() will modify
+	 * it.
+	 */
+	pci_set_master(pdev);
 
-		/* OpenFirmware on Mac's does not set this - DOH.. */ 
-		if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
-			printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
-			       "access - was not enabled by BIOS/Firmware\n",
-			       dev->name);
-			ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY;
-			pci_write_config_word(ap->pdev, PCI_COMMAND,
-					      ap->pci_command);
-			wmb();
-		}
+	pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
 
-		pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
-				     &ap->pci_latency);
-		if (ap->pci_latency <= 0x40) {
-			ap->pci_latency = 0x40;
-			pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
-					      ap->pci_latency);
-		}
+	/* OpenFirmware on Mac's does not set this - DOH.. */ 
+	if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
+		printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
+		       "access - was not enabled by BIOS/Firmware\n",
+		       dev->name);
+		ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY;
+		pci_write_config_word(ap->pdev, PCI_COMMAND,
+				      ap->pci_command);
+		wmb();
+	}
 
-		/*
-		 * Remap the regs into kernel space - this is abuse of
-		 * dev->base_addr since it was means for I/O port
-		 * addresses but who gives a damn.
-		 */
-		dev->base_addr = pci_resource_start(pdev, 0);
-		ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
-		if (!ap->regs) {
-			printk(KERN_ERR "%s:  Unable to map I/O register, "
-			       "AceNIC %i will be disabled.\n",
-			       dev->name, boards_found);
-			break;
-		}
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ap->pci_latency);
+	if (ap->pci_latency <= 0x40) {
+		ap->pci_latency = 0x40;
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ap->pci_latency);
+	}
 
-		switch(pdev->vendor) {
-		case PCI_VENDOR_ID_ALTEON:
-			if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) {
-				strncpy(ap->name, "Farallon PN9100-T "
-					"Gigabit Ethernet", sizeof (ap->name));
-				printk(KERN_INFO "%s: Farallon PN9100-T ",
-				       dev->name);
-			} else {
-				strncpy(ap->name, "AceNIC Gigabit Ethernet",
-					sizeof (ap->name));
-				printk(KERN_INFO "%s: Alteon AceNIC ",
-				       dev->name);
-			}
-			break;
-		case PCI_VENDOR_ID_3COM:
-			strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
-				sizeof (ap->name));
-			printk(KERN_INFO "%s: 3Com 3C985 ", dev->name);
-			break;
-		case PCI_VENDOR_ID_NETGEAR:
-			strncpy(ap->name, "NetGear GA620 Gigabit Ethernet",
-				sizeof (ap->name));
-			printk(KERN_INFO "%s: NetGear GA620 ", dev->name);
-			break;
-		case PCI_VENDOR_ID_DEC:
-			if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) {
-				strncpy(ap->name, "Farallon PN9000-SX "
-					"Gigabit Ethernet", sizeof (ap->name));
-				printk(KERN_INFO "%s: Farallon PN9000-SX ",
-				       dev->name);
-				break;
-			}
-		case PCI_VENDOR_ID_SGI:
-			strncpy(ap->name, "SGI AceNIC Gigabit Ethernet",
+	/*
+	 * Remap the regs into kernel space - this is abuse of
+	 * dev->base_addr since it was means for I/O port
+	 * addresses but who gives a damn.
+	 */
+	dev->base_addr = pci_resource_start(pdev, 0);
+	ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
+	if (!ap->regs) {
+		printk(KERN_ERR "%s:  Unable to map I/O register, "
+		       "AceNIC %i will be disabled.\n",
+		       dev->name, boards_found);
+		goto fail_free_netdev;
+	}
+
+	switch(pdev->vendor) {
+	case PCI_VENDOR_ID_ALTEON:
+		if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) {
+			strncpy(ap->name, "Farallon PN9100-T "
+				"Gigabit Ethernet", sizeof (ap->name));
+			printk(KERN_INFO "%s: Farallon PN9100-T ",
+			       dev->name);
+		} else {
+			strncpy(ap->name, "AceNIC Gigabit Ethernet",
 				sizeof (ap->name));
-			printk(KERN_INFO "%s: SGI AceNIC ", dev->name);
-			break;
-		default:
- 			strncpy(ap->name, "Unknown AceNIC based Gigabit "
-				"Ethernet", sizeof (ap->name));
-			printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
+			printk(KERN_INFO "%s: Alteon AceNIC ",
+			       dev->name);
+		}
+		break;
+	case PCI_VENDOR_ID_3COM:
+		strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
+			sizeof (ap->name));
+		printk(KERN_INFO "%s: 3Com 3C985 ", dev->name);
+		break;
+	case PCI_VENDOR_ID_NETGEAR:
+		strncpy(ap->name, "NetGear GA620 Gigabit Ethernet",
+			sizeof (ap->name));
+		printk(KERN_INFO "%s: NetGear GA620 ", dev->name);
+		break;
+	case PCI_VENDOR_ID_DEC:
+		if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) {
+			strncpy(ap->name, "Farallon PN9000-SX "
+				"Gigabit Ethernet", sizeof (ap->name));
+			printk(KERN_INFO "%s: Farallon PN9000-SX ",
+			       dev->name);
 			break;
 		}
-		ap->name [sizeof (ap->name) - 1] = '\0';
-		printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
+	case PCI_VENDOR_ID_SGI:
+		strncpy(ap->name, "SGI AceNIC Gigabit Ethernet",
+			sizeof (ap->name));
+		printk(KERN_INFO "%s: SGI AceNIC ", dev->name);
+		break;
+	default:
+ 		strncpy(ap->name, "Unknown AceNIC based Gigabit "
+			"Ethernet", sizeof (ap->name));
+		printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
+		break;
+	}
+
+	ap->name [sizeof (ap->name) - 1] = '\0';
+	printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
 #ifdef __sparc__
-		printk("irq %s\n", __irq_itoa(pdev->irq));
+	printk("irq %s\n", __irq_itoa(pdev->irq));
 #else
-		printk("irq %i\n", pdev->irq);
+	printk("irq %i\n", pdev->irq);
 #endif
 
 #ifdef CONFIG_ACENIC_OMIT_TIGON_I
-		if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
-			printk(KERN_ERR "%s: Driver compiled without Tigon I"
-			       " support - NIC disabled\n", dev->name);
-			ace_init_cleanup(dev);
-			free_netdev(dev);
-			continue;
-		}
+	if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
+		printk(KERN_ERR "%s: Driver compiled without Tigon I"
+		       " support - NIC disabled\n", dev->name);
+		goto fail_uninit;
+	}
 #endif
 
-		if (ace_allocate_descriptors(dev)) {
-			/*
-			 * ace_allocate_descriptors() calls
-			 * ace_init_cleanup() on error.
-			 */
-			free_netdev(dev);
-			continue;
-		}
+	if (ace_allocate_descriptors(dev))
+		goto fail_free_netdev;
 
 #ifdef MODULE
-		if (boards_found >= ACE_MAX_MOD_PARMS)
-			ap->board_idx = BOARD_IDX_OVERFLOW;
-		else
-			ap->board_idx = boards_found;
+	if (boards_found >= ACE_MAX_MOD_PARMS)
+		ap->board_idx = BOARD_IDX_OVERFLOW;
+	else
+		ap->board_idx = boards_found;
 #else
-		ap->board_idx = BOARD_IDX_STATIC;
+	ap->board_idx = BOARD_IDX_STATIC;
 #endif
 
-		if (ace_init(dev)) {
-			/*
-			 * ace_init() calls ace_init_cleanup() on error.
-			 */
-			free_netdev(dev);
-			continue;
-		}
+	if (ace_init(dev))
+		goto fail_free_netdev;
 
-		if (register_netdev(dev)) {
-			printk(KERN_ERR "acenic: device registration failed\n");
-			ace_init_cleanup(dev);
-			free_netdev(dev);
-			continue;
-		}
-
-		if (ap->pci_using_dac)
-			dev->features |= NETIF_F_HIGHDMA;
-
-		boards_found++;
+	if (register_netdev(dev)) {
+		printk(KERN_ERR "acenic: device registration failed\n");
+		goto fail_uninit;
 	}
 
-	/*
-	 * If we're at this point we're going through ace_probe() for
-	 * the first time.  Return success (0) if we've initialized 1
-	 * or more boards. Otherwise, return failure (-ENODEV).
-	 */
-
-	if (boards_found > 0)
-		return 0;
-	else
-		return -ENODEV;
-}
+	if (ap->pci_using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
 
+	pci_set_drvdata(pdev, dev);
 
-#ifdef MODULE
-MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
-MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(tx_ratio, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state");
-MODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level");
-MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives");
-MODULE_PARM_DESC(max_tx_desc, "AceNIC/3C985/GA620 max number of transmit descriptors to wait");
-MODULE_PARM_DESC(rx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first rx descriptor arrives");
-MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descriptors to wait");
-MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)");
-#endif
+	boards_found++;
+	return 0;
 
+ fail_uninit:
+	ace_init_cleanup(dev);
+ fail_free_netdev:
+	free_netdev(dev);
+	return -ENODEV;
+}
 
-static void __exit ace_module_cleanup(void)
+static void __devexit acenic_remove_one(struct pci_dev *pdev)
 {
-	struct ace_private *ap;
-	struct ace_regs *regs;
-	struct net_device *next;
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct ace_private *ap = dev->priv;
+	struct ace_regs *regs = ap->regs;
 	short i;
 
-	while (root_dev) {
-		ap = root_dev->priv;
-		next = ap->next;
-		unregister_netdev(root_dev);
+	unregister_netdev(dev);
 
-		regs = ap->regs;
-
-		writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
-		if (ap->version >= 2)
-			writel(readl(&regs->CpuBCtrl) | CPU_HALT,
-			       &regs->CpuBCtrl);
-		/*
-		 * This clears any pending interrupts
-		 */
-		writel(1, &regs->Mb0Lo);
-		readl(&regs->CpuCtrl);	/* flush */
+	writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
+	if (ap->version >= 2)
+		writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
+	
+	/*
+	 * This clears any pending interrupts
+	 */
+	writel(1, &regs->Mb0Lo);
+	readl(&regs->CpuCtrl);	/* flush */
 
-		/*
-		 * Make sure no other CPUs are processing interrupts
-		 * on the card before the buffers are being released.
-		 * Otherwise one might experience some `interesting'
-		 * effects.
-		 *
-		 * Then release the RX buffers - jumbo buffers were
-		 * already released in ace_close().
-		 */
-		ace_sync_irq(root_dev->irq);
+	/*
+	 * Make sure no other CPUs are processing interrupts
+	 * on the card before the buffers are being released.
+	 * Otherwise one might experience some `interesting'
+	 * effects.
+	 *
+	 * Then release the RX buffers - jumbo buffers were
+	 * already released in ace_close().
+	 */
+	ace_sync_irq(dev->irq);
 
-		for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
-			struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
+	for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
+		struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
 
-			if (skb) {
-				struct ring_info *ringp;
-				dma_addr_t mapping;
+		if (skb) {
+			struct ring_info *ringp;
+			dma_addr_t mapping;
 
-				ringp = &ap->skb->rx_std_skbuff[i];
-				mapping = pci_unmap_addr(ringp, mapping);
-				pci_unmap_page(ap->pdev, mapping,
-					       ACE_STD_BUFSIZE - (2 + 16),
-					       PCI_DMA_FROMDEVICE);
+			ringp = &ap->skb->rx_std_skbuff[i];
+			mapping = pci_unmap_addr(ringp, mapping);
+			pci_unmap_page(ap->pdev, mapping,
+				       ACE_STD_BUFSIZE - (2 + 16),
+				       PCI_DMA_FROMDEVICE);
 
-				ap->rx_std_ring[i].size = 0;
-				ap->skb->rx_std_skbuff[i].skb = NULL;
-				dev_kfree_skb(skb);
-			}
-		}
-		if (ap->version >= 2) {
-			for (i = 0; i < RX_MINI_RING_ENTRIES; i++) {
-				struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
-
-				if (skb) {
-					struct ring_info *ringp;
-					dma_addr_t mapping;
-
-					ringp = &ap->skb->rx_mini_skbuff[i];
-					mapping = pci_unmap_addr(ringp,mapping);
-					pci_unmap_page(ap->pdev, mapping,
-						       ACE_MINI_BUFSIZE - (2 + 16),
-						       PCI_DMA_FROMDEVICE);
-
-					ap->rx_mini_ring[i].size = 0;
-					ap->skb->rx_mini_skbuff[i].skb = NULL;
-					dev_kfree_skb(skb);
-				}
-			}
+			ap->rx_std_ring[i].size = 0;
+			ap->skb->rx_std_skbuff[i].skb = NULL;
+			dev_kfree_skb(skb);
 		}
-		for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
-			struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
+	}
+
+	if (ap->version >= 2) {
+		for (i = 0; i < RX_MINI_RING_ENTRIES; i++) {
+			struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
+
 			if (skb) {
 				struct ring_info *ringp;
 				dma_addr_t mapping;
 
-				ringp = &ap->skb->rx_jumbo_skbuff[i];
-				mapping = pci_unmap_addr(ringp, mapping);
+				ringp = &ap->skb->rx_mini_skbuff[i];
+				mapping = pci_unmap_addr(ringp,mapping);
 				pci_unmap_page(ap->pdev, mapping,
-					       ACE_JUMBO_BUFSIZE - (2 + 16),
+					       ACE_MINI_BUFSIZE - (2 + 16),
 					       PCI_DMA_FROMDEVICE);
 
-				ap->rx_jumbo_ring[i].size = 0;
-				ap->skb->rx_jumbo_skbuff[i].skb = NULL;
+				ap->rx_mini_ring[i].size = 0;
+				ap->skb->rx_mini_skbuff[i].skb = NULL;
 				dev_kfree_skb(skb);
 			}
 		}
-
-		ace_init_cleanup(root_dev);
-		free_netdev(root_dev);
-		root_dev = next;
 	}
-}
 
+	for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
+		struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
+		if (skb) {
+			struct ring_info *ringp;
+			dma_addr_t mapping;
 
-int __init ace_module_init(void)
-{
-	int status;
+			ringp = &ap->skb->rx_jumbo_skbuff[i];
+			mapping = pci_unmap_addr(ringp, mapping);
+			pci_unmap_page(ap->pdev, mapping,
+				       ACE_JUMBO_BUFSIZE - (2 + 16),
+				       PCI_DMA_FROMDEVICE);
 
-	root_dev = NULL;
+			ap->rx_jumbo_ring[i].size = 0;
+			ap->skb->rx_jumbo_skbuff[i].skb = NULL;
+			dev_kfree_skb(skb);
+		}
+	}
 
-#ifdef NEW_NETINIT
-	status = acenic_probe();
-#else
-	status = acenic_probe(NULL);
-#endif
-	return status;
+	ace_init_cleanup(dev);
+	free_netdev(dev);
 }
 
+static struct pci_driver acenic_pci_driver = {
+	.name		= "acenic",
+	.id_table	= acenic_pci_tbl,
+	.probe		= acenic_probe_one,
+	.remove		= __devexit_p(acenic_remove_one),
+};
 
-#if (LINUX_VERSION_CODE < 0x02032a)
-#ifdef MODULE
-int init_module(void)
+static int __init acenic_init(void)
 {
-	return ace_module_init();
+	return pci_module_init(&acenic_pci_driver);
 }
 
-
-void cleanup_module(void)
+static void __exit acenic_exit(void)
 {
-	ace_module_cleanup();
+	pci_unregister_driver(&acenic_pci_driver);
 }
-#endif
-#else
-module_init(ace_module_init);
-module_exit(ace_module_cleanup);
-#endif
 
+module_init(acenic_init);
+module_exit(acenic_exit);
 
 static void ace_free_descriptors(struct net_device *dev)
 {
@@ -1462,13 +1203,6 @@
 	} else
 		dev->irq = pdev->irq;
 
-	/*
-	 * Register the device here to be able to catch allocated
-	 * interrupt handlers in case the firmware doesn't come up.
-	 */
-	ap->next = root_dev;
-	root_dev = dev;
-
 #ifdef INDEX_DEBUG
 	spin_lock_init(&ap->debug_lock);
 	ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1;
@@ -2642,8 +2376,6 @@
 
 	netif_start_queue(dev);
 
-	ACE_MOD_INC_USE_COUNT;
-
 	/*
 	 * Setup the bottom half rx ring refill handler
 	 */
@@ -2660,8 +2392,6 @@
 	unsigned long flags;
 	short i;
 
-	ace_if_down(dev);
-
 	/*
 	 * Without (or before) releasing irq and stopping hardware, this
 	 * is an absolute non-sense, by the way. It will be reset instantly
@@ -2733,7 +2463,6 @@
 	ace_unmask_irq(dev);
 	local_irq_restore(flags);
 
-	ACE_MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -2790,12 +2519,6 @@
 	struct tx_desc *desc;
 	u32 idx, flagsize;
 
- 	/*
-	 * This only happens with pre-softnet, ie. 2.2.x kernels.
- 	 */
-	if (early_stop_netif_stop_queue(dev))
- 		return 1;
-
 restart:
 	idx = ap->tx_prd;
 
--- diff/drivers/net/at1700.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/at1700.c	2004-05-27 18:34:17.000000000 +0100
@@ -80,17 +80,10 @@
  *	ISA
  */
 
-#ifndef CONFIG_X86_PC9800
 static unsigned at1700_probe_list[] __initdata = {
 	0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
 };
 
-#else /* CONFIG_X86_PC9800 */
-static unsigned at1700_probe_list[] __initdata = {
-	0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0
-};
-
-#endif /* CONFIG_X86_PC9800 */
 /*
  *	MCA
  */
@@ -133,7 +126,6 @@
 
 
 /* Offsets from the base address. */
-#ifndef CONFIG_X86_PC9800
 #define STATUS			0
 #define TX_STATUS		0
 #define RX_STATUS		1
@@ -161,34 +153,6 @@
 #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
@@ -230,11 +194,7 @@
    (detachable devices only).
    */
 
-#ifndef CONFIG_X86_PC9800
 static int io = 0x260;
-#else
-static int io = 0xd0;
-#endif
 
 static int irq;
 
@@ -246,15 +206,7 @@
 		mca_mark_as_unused(lp->mca_slot);
 #endif	
 	free_irq(dev->irq, NULL);
-#ifndef CONFIG_X86_PC9800
 	release_region(dev->base_addr, AT1700_IO_EXTENT);
-#else
-	{
-		int i;
-		for (i = 0; i < 0x2000; i += 0x200)
-			release_region(dev->base_addr + i, 2);
-	}
-#endif
 }
 
 struct net_device * __init at1700_probe(int unit)
@@ -321,20 +273,8 @@
 	int slot, ret = -ENODEV;
 	struct net_local *lp = netdev_priv(dev);
 
-#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
@@ -425,15 +365,8 @@
 	outb(0, ioaddr + RESET);
 
 	if (is_at1700) {
-#ifndef CONFIG_X86_PC9800
 		irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
 						   | (read_eeprom(ioaddr, 0)>>14)];
-#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. */
@@ -517,11 +450,7 @@
 	/* 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)
@@ -552,12 +481,7 @@
 	return 0;
 
 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;
 }
 
@@ -568,13 +492,6 @@
 #define EE_DATA_WRITE	0x80	/* EEPROM chip data in, in reg. 17. */
 #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)
 #define EE_READ_CMD		(6 << 6)
@@ -593,22 +510,17 @@
 		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
 		outb(EE_CS, ee_addr);
 		outb(dataval, ee_daddr);
-		eeprom_delay();
 		outb(EE_CS | EE_SHIFT_CLK, ee_addr);	/* EEPROM clock tick. */
-		eeprom_delay();
 	}
 	outb(EE_DATA_WRITE, ee_daddr);
 	for (i = 16; i > 0; i--) {
 		outb(EE_CS, ee_addr);
-		eeprom_delay();
 		outb(EE_CS | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay();
 		retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0);
 	}
 
 	/* Terminate the EEPROM access. */
 	outb(EE_CS, ee_addr);
-	eeprom_delay();
 	outb(EE_SHIFT_CLK, ee_addr);
 	outb(0, ee_addr);
 	return retval;
--- diff/drivers/net/e1000/e1000_ethtool.c	2004-05-19 22:11:57.000000000 +0100
+++ source/drivers/net/e1000/e1000_ethtool.c	2004-05-27 18:34:17.000000000 +0100
@@ -53,7 +53,7 @@
 
 #define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
 		      offsetof(struct e1000_adapter, m)
-static struct e1000_stats e1000_gstrings_stats[] = {
+static const struct e1000_stats e1000_gstrings_stats[] = {
 	{ "rx_packets", E1000_STAT(net_stats.rx_packets) },
 	{ "tx_packets", E1000_STAT(net_stats.tx_packets) },
 	{ "rx_bytes", E1000_STAT(net_stats.rx_bytes) },
@@ -100,9 +100,10 @@
 };
 #define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
 
-static void
-e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
+static int
+e1000_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
+	struct e1000_adapter *adapter = netdev_priv(dev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	if(hw->media_type == e1000_media_type_copper) {
@@ -169,11 +170,13 @@
 	}
 
 	ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+	return 0;
 }
 
 static int
-e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
+e1000_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
+	struct e1000_adapter *adapter = netdev_priv(dev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	if(ecmd->autoneg == AUTONEG_ENABLE) {
@@ -195,10 +198,11 @@
 	return 0;
 }
 
-static int
-e1000_ethtool_gpause(struct e1000_adapter *adapter,
+static void
+e1000_get_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *epause)
 {
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	
 	epause->autoneg = 
@@ -212,14 +216,13 @@
 		epause->rx_pause = 1;
 		epause->tx_pause = 1;
 	}
-	
-	return 0;
 }
 
 static int
-e1000_ethtool_spause(struct e1000_adapter *adapter,
+e1000_set_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *epause)
 {
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	
 	adapter->fc_autoneg = epause->autoneg;
@@ -248,28 +251,95 @@
 	return 0;
 }
 
+static u32
+e1000_get_rx_csum(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	return adapter->rx_csum;
+}
+
+static int
+e1000_set_rx_csum(struct net_device *netdev, u32 data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	adapter->rx_csum = data;
+	if(netif_running(netdev)) {
+		e1000_down(adapter);
+		e1000_up(adapter);
+	} else
+		e1000_reset(adapter);
+	return 0;
+}
+
+static u32
+e1000_get_tx_csum(struct net_device *netdev)
+{
+	return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static int
+e1000_set_tx_csum(struct net_device *netdev, u32 data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if(adapter->hw.mac_type < e1000_82543)
+		return data ? -EINVAL : 0;
+
+	if (data)
+		netdev->features |= NETIF_F_HW_CSUM;
+	else
+		netdev->features &= ~NETIF_F_HW_CSUM;
+	return 0;
+}
+
+static int
+e1000_set_tso(struct net_device *netdev, u32 data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if (adapter->hw.mac_type < e1000_82544 ||
+	     adapter->hw.mac_type == e1000_82547)
+		return data ? -EINVAL : 0;
+		
+	if (data)
+		netdev->features |= NETIF_F_TSO;
+	else
+		netdev->features &= ~NETIF_F_TSO;
+	return 0;
+}
+
+
 static void
-e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
-                       struct ethtool_drvinfo *drvinfo)
+e1000_get_drvinfo(struct net_device *dev, 
+		  struct ethtool_drvinfo *drvinfo)
 {
+	struct e1000_adapter *adapter = netdev_priv(dev);
+
 	strncpy(drvinfo->driver,  e1000_driver_name, 32);
 	strncpy(drvinfo->version, e1000_driver_version, 32);
 	strncpy(drvinfo->fw_version, "N/A", 32);
 	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
-	drvinfo->n_stats = E1000_STATS_LEN;
-	drvinfo->testinfo_len = E1000_TEST_LEN;
+}
+
+static int
+e1000_get_regs_len(struct net_device *dev)
+{
 #define E1000_REGS_LEN 32
-	drvinfo->regdump_len  = E1000_REGS_LEN * sizeof(uint32_t);
-	drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2;
+	return E1000_REGS_LEN * sizeof(uint32_t);
 }
 
 static void
-e1000_ethtool_gregs(struct e1000_adapter *adapter,
-                    struct ethtool_regs *regs, uint32_t *regs_buff)
+e1000_get_regs(struct net_device *dev,
+	       struct ethtool_regs *regs, void *p)
 {
+	struct e1000_adapter *adapter = netdev_priv(dev);
 	struct e1000_hw *hw = &adapter->hw;
+	u32 *regs_buff = p;
 	uint16_t phy_data;
 
+	memset(p, 0, E1000_REGS_LEN * sizeof(uint32_t));
+
 	regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
 
 	regs_buff[0]  = E1000_READ_REG(hw, CTRL);
@@ -342,30 +412,36 @@
 	e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
 	regs_buff[24] = (uint32_t)phy_data;  /* phy local receiver status */
 	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */
+}
 
-	return;
+static int
+e1000_get_eeprom_len(struct net_device *dev)
+{
+	struct e1000_adapter *adapter = netdev_priv(dev);
+
+	return adapter->hw.eeprom.word_size * 2;
 }
 
 static int
-e1000_ethtool_geeprom(struct e1000_adapter *adapter,
-                      struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
+e1000_get_eeprom(struct net_device *dev,
+		 struct ethtool_eeprom *eeprom, u8 *bytes)
 {
+	struct e1000_adapter *adapter = netdev_priv(dev);
 	struct e1000_hw *hw = &adapter->hw;
+	uint16_t *eeprom_buff = (uint16_t *) bytes;
 	int first_word, last_word;
 	int ret_val = 0;
 	uint16_t i;
 
-	if(eeprom->len == 0) {
-		ret_val = -EINVAL;
-		goto geeprom_error;
-	}
+	if(eeprom->len == 0) 
+		return  -EINVAL;
 
 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 
-	if(eeprom->offset > eeprom->offset + eeprom->len) {
-		ret_val = -EINVAL;
-		goto geeprom_error;
-	}
+	if(eeprom->offset > eeprom->offset + eeprom->len) 
+		return -EINVAL;
+
+	memset(bytes, 0, adapter->hw.eeprom.word_size*2);
 
 	if((eeprom->offset + eeprom->len) > (hw->eeprom.word_size * 2))
 		eeprom->len = ((hw->eeprom.word_size * 2) - eeprom->offset);
@@ -388,14 +464,14 @@
 	for (i = 0; i < last_word - first_word + 1; i++)
 		le16_to_cpus(&eeprom_buff[i]);
 
-geeprom_error:
 	return ret_val;
 }
 
 static int
-e1000_ethtool_seeprom(struct e1000_adapter *adapter,
-                      struct ethtool_eeprom *eeprom, void *user_data)
+e1000_set_eeprom(struct net_device *netdev,
+		 struct ethtool_eeprom *eeprom, u8 *bytes)
 {
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	uint16_t *eeprom_buff;
 	void *ptr;
@@ -439,11 +515,7 @@
 	for (i = 0; i < last_word - first_word + 1; i++)
 		le16_to_cpus(&eeprom_buff[i]);
 
-	if((ret_val != 0) || copy_from_user(ptr, user_data, eeprom->len)) {
-		ret_val = -EFAULT;
-		goto seeprom_error;
-	}
-
+	memcpy(ptr, bytes, eeprom->len);
 	for (i = 0; i < last_word - first_word + 1; i++)
 		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
 
@@ -454,15 +526,15 @@
 	if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG)
 		e1000_update_eeprom_checksum(hw);
 
-seeprom_error:
 	kfree(eeprom_buff);
 	return ret_val;
 }
 
-static int
-e1000_ethtool_gring(struct e1000_adapter *adapter,
+static void
+e1000_get_ringparam(struct net_device *netdev,
                     struct ethtool_ringparam *ring)
 {
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	e1000_mac_type mac_type = adapter->hw.mac_type;
 	struct e1000_desc_ring *txdr = &adapter->tx_ring;
 	struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -477,13 +549,12 @@
 	ring->tx_pending = txdr->count;
 	ring->rx_mini_pending = 0;
 	ring->rx_jumbo_pending = 0;
-
-	return 0;
 }
+
 static int 
-e1000_ethtool_sring(struct e1000_adapter *adapter,
-                    struct ethtool_ringparam *ring)
+e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
 {
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int err;
 	e1000_mac_type mac_type = adapter->hw.mac_type;
 	struct e1000_desc_ring *txdr = &adapter->tx_ring;
@@ -806,8 +877,6 @@
 		kfree(txdr->buffer_info);
 	if(rxdr->buffer_info)
 		kfree(rxdr->buffer_info);
-
-	return;
 }
 
 static int
@@ -939,8 +1008,6 @@
 	e1000_write_phy_reg(&adapter->hw, 30, 0x8FFC);
 	e1000_write_phy_reg(&adapter->hw, 29, 0x001A);
 	e1000_write_phy_reg(&adapter->hw, 30, 0x8FF0);
-
-	return;
 }
 
 static void
@@ -1257,11 +1324,19 @@
 	return *data;
 }
 
+
 static int
-e1000_ethtool_test(struct e1000_adapter *adapter,
-		   struct ethtool_test *eth_test, uint64_t *data)
+e1000_diag_test_count(struct net_device *dev)
 {
-	boolean_t if_running = netif_running(adapter->netdev);
+	return E1000_TEST_LEN;
+}
+
+static void 
+e1000_diag_test(struct net_device *netdev,
+		struct ethtool_test *eth_test, u64 *data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	boolean_t if_running = netif_running(netdev);
 
 	if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
 		/* Offline tests */
@@ -1305,12 +1380,12 @@
 		data[2] = 0;
 		data[3] = 0;
 	}
-	return 0;
 }
 
 static void
-e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
+e1000_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
+	struct e1000_adapter *adapter = netdev_priv(dev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	switch(adapter->hw.device_id) {
@@ -1348,10 +1423,10 @@
 		return;
 	}
 }
-
 static int
-e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
+e1000_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
+	struct e1000_adapter *adapter = netdev_priv(dev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	switch(adapter->hw.device_id) {
@@ -1408,8 +1483,13 @@
 }
 
 static int
-e1000_ethtool_led_blink(struct e1000_adapter *adapter, struct ethtool_value *id)
+e1000_phys_id(struct net_device *netdev, u32 data)
 {
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+		data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
 	if(!adapter->blink_timer.function) {
 		init_timer(&adapter->blink_timer);
 		adapter->blink_timer.function = e1000_led_blink_callback;
@@ -1420,11 +1500,7 @@
 	mod_timer(&adapter->blink_timer, jiffies);
 
 	set_current_state(TASK_INTERRUPTIBLE);
-	if(id->data)
-		schedule_timeout(id->data * HZ);
-	else
-		schedule_timeout(MAX_SCHEDULE_TIMEOUT);
-
+	schedule_timeout(data * HZ);
 	del_timer_sync(&adapter->blink_timer);
 	e1000_led_off(&adapter->hw);
 	clear_bit(E1000_LED_ON, &adapter->led_status);
@@ -1433,345 +1509,89 @@
 	return 0;
 }
 
-int
-e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
+static int
+e1000_nway_reset(struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = netdev->priv;
-	void *addr = ifr->ifr_data;
-	uint32_t cmd;
-
-	if(get_user(cmd, (uint32_t *) addr))
-		return -EFAULT;
-
-	switch(cmd) {
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = {ETHTOOL_GSET};
-		e1000_ethtool_gset(adapter, &ecmd);
-		if(copy_to_user(addr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SSET: {
-		struct ethtool_cmd ecmd;
-		if(copy_from_user(&ecmd, addr, sizeof(ecmd)))
-			return -EFAULT;
-		return e1000_ethtool_sset(adapter, &ecmd);
-	}
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo drvinfo = {ETHTOOL_GDRVINFO};
-		e1000_ethtool_gdrvinfo(adapter, &drvinfo);
-		if(copy_to_user(addr, &drvinfo, sizeof(drvinfo)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GSTRINGS: {
-		struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
-		char *strings = NULL;
-		int err = 0;
-
-		if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
-			return -EFAULT;
-		switch(gstrings.string_set) {
-		case ETH_SS_TEST:
-			gstrings.len = E1000_TEST_LEN;
-			strings = kmalloc(E1000_TEST_LEN * ETH_GSTRING_LEN,
-					  GFP_KERNEL);
-			if(!strings)
-				return -ENOMEM;
-			memcpy(strings, e1000_gstrings_test, E1000_TEST_LEN *
-			       ETH_GSTRING_LEN);
-			break;
-		case ETH_SS_STATS: {
-			int i;
-			gstrings.len = E1000_STATS_LEN;
-			strings = kmalloc(E1000_STATS_LEN * ETH_GSTRING_LEN,
-					  GFP_KERNEL);
-			if(!strings)
-				return -ENOMEM;
-			for(i=0; i < E1000_STATS_LEN; i++) {
-				memcpy(&strings[i * ETH_GSTRING_LEN],
-				       e1000_gstrings_stats[i].stat_string,
-				       ETH_GSTRING_LEN);
-			}
-			break;
-		}
-		default:
-			return -EOPNOTSUPP;
-		}
-		if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
-			err = -EFAULT;
-		addr += offsetof(struct ethtool_gstrings, data);
-		if(!err && copy_to_user(addr, strings,
-		   gstrings.len * ETH_GSTRING_LEN))
-			err = -EFAULT;
-
-		kfree(strings);
-		return err;
-	}
-	case ETHTOOL_GREGS: {
-		struct ethtool_regs regs = {ETHTOOL_GREGS};
-		uint32_t regs_buff[E1000_REGS_LEN];
-
-		if(copy_from_user(&regs, addr, sizeof(regs)))
-			return -EFAULT;
-		memset(regs_buff, 0, sizeof(regs_buff));
-		if (regs.len > E1000_REGS_LEN)
-			regs.len = E1000_REGS_LEN;
-		e1000_ethtool_gregs(adapter, &regs, regs_buff);
-		if(copy_to_user(addr, &regs, sizeof(regs)))
-			return -EFAULT;
-
-		addr += offsetof(struct ethtool_regs, data);
-		if(copy_to_user(addr, regs_buff, regs.len))
-			return -EFAULT;
-
-		return 0;
-	}
-	case ETHTOOL_NWAY_RST: {
-		if(netif_running(netdev)) {
-			e1000_down(adapter);
-			e1000_up(adapter);
-		}
-		return 0;
-	}
-	case ETHTOOL_PHYS_ID: {
-		struct ethtool_value id;
-		if(copy_from_user(&id, addr, sizeof(id)))
-			return -EFAULT;
-		return e1000_ethtool_led_blink(adapter, &id);
-	}
-	case ETHTOOL_GLINK: {
-		struct ethtool_value link = {ETHTOOL_GLINK};
-		link.data = netif_carrier_ok(netdev);
-		if(copy_to_user(addr, &link, sizeof(link)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GWOL: {
-		struct ethtool_wolinfo wol = {ETHTOOL_GWOL};
-		e1000_ethtool_gwol(adapter, &wol);
-		if(copy_to_user(addr, &wol, sizeof(wol)) != 0)
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SWOL: {
-		struct ethtool_wolinfo wol;
-		if(copy_from_user(&wol, addr, sizeof(wol)) != 0)
-			return -EFAULT;
-		return e1000_ethtool_swol(adapter, &wol);
-	}
-	case ETHTOOL_GEEPROM: {
-		struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
-		struct e1000_hw *hw = &adapter->hw;
-		uint16_t *eeprom_buff;
-		void *ptr;
-		int err = 0;
-
-		if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
-			return -EFAULT;
-
-		eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL);
-
-		if(!eeprom_buff)
-			return -ENOMEM;
-
-		if((err = e1000_ethtool_geeprom(adapter, &eeprom,
-						eeprom_buff)))
-			goto err_geeprom_ioctl;
-
-		if(copy_to_user(addr, &eeprom, sizeof(eeprom))) {
-			err = -EFAULT;
-			goto err_geeprom_ioctl;
-		}
-
-		addr += offsetof(struct ethtool_eeprom, data);
-		ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);
-
-		if(copy_to_user(addr, ptr, eeprom.len))
-			err = -EFAULT;
-
-err_geeprom_ioctl:
-		kfree(eeprom_buff);
-		return err;
-	}
-	case ETHTOOL_SEEPROM: {
-		struct ethtool_eeprom eeprom;
-
-		if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
-			return -EFAULT;
-
-		addr += offsetof(struct ethtool_eeprom, data);
-		return e1000_ethtool_seeprom(adapter, &eeprom, addr);
-	}
-	case ETHTOOL_GRINGPARAM: {
-		struct ethtool_ringparam ering = {ETHTOOL_GRINGPARAM};
-		e1000_ethtool_gring(adapter, &ering);
-		if(copy_to_user(addr, &ering, sizeof(ering)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SRINGPARAM: {
-		struct ethtool_ringparam ering;
-		if(copy_from_user(&ering, addr, sizeof(ering)))
-			return -EFAULT;
-		return e1000_ethtool_sring(adapter, &ering);
-	}
-	case ETHTOOL_GPAUSEPARAM: {
-		struct ethtool_pauseparam epause = {ETHTOOL_GPAUSEPARAM};
-		e1000_ethtool_gpause(adapter, &epause);
-		if(copy_to_user(addr, &epause, sizeof(epause)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SPAUSEPARAM: {
-		struct ethtool_pauseparam epause;
-		if(copy_from_user(&epause, addr, sizeof(epause)))
-			return -EFAULT;
-		return e1000_ethtool_spause(adapter, &epause);
-	}
-	case ETHTOOL_GSTATS: {
-		struct {
-			struct ethtool_stats eth_stats;
-			uint64_t data[E1000_STATS_LEN];
-		} stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} };
-		int i;
-
-		e1000_update_stats(adapter);
-		for(i = 0; i < E1000_STATS_LEN; i++)
-			stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
-					sizeof(uint64_t)) ?
-				*(uint64_t *)((char *)adapter +
-					e1000_gstrings_stats[i].stat_offset) :
-				*(uint32_t *)((char *)adapter +
-					e1000_gstrings_stats[i].stat_offset);
-		if(copy_to_user(addr, &stats, sizeof(stats)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_TEST: {
-		struct {
-			struct ethtool_test eth_test;
-			uint64_t data[E1000_TEST_LEN];
-		} test = { {ETHTOOL_TEST} };
-		int err;
-
-		if(copy_from_user(&test.eth_test, addr, sizeof(test.eth_test)))
-			return -EFAULT;
-
-		test.eth_test.len = E1000_TEST_LEN;
-
-		if((err = e1000_ethtool_test(adapter, &test.eth_test,
-					     test.data)))
-			return err;
-
-		if(copy_to_user(addr, &test, sizeof(test)) != 0)
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GRXCSUM: {
-		struct ethtool_value edata = { ETHTOOL_GRXCSUM };
-
-		edata.data = adapter->rx_csum;
-		if (copy_to_user(addr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SRXCSUM: {
-		struct ethtool_value edata;
-
-		if (copy_from_user(&edata, addr, sizeof(edata)))
-			return -EFAULT;
-		adapter->rx_csum = edata.data;
-		if(netif_running(netdev)) {
-			e1000_down(adapter);
-			e1000_up(adapter);
-		} else
-			e1000_reset(adapter);
-		return 0;
-	}
-	case ETHTOOL_GTXCSUM: {
-		struct ethtool_value edata = { ETHTOOL_GTXCSUM };
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
-		edata.data =
-			(netdev->features & NETIF_F_HW_CSUM) != 0;
-		if (copy_to_user(addr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
+	if(netif_running(netdev)) {
+		e1000_down(adapter);
+		e1000_up(adapter);
 	}
-	case ETHTOOL_STXCSUM: {
-		struct ethtool_value edata;
-
-		if (copy_from_user(&edata, addr, sizeof(edata)))
-			return -EFAULT;
-
-		if(adapter->hw.mac_type < e1000_82543) {
-			if (edata.data != 0)
-				return -EINVAL;
-			return 0;
-		}
+	return 0;
+}
 
-		if (edata.data)
-			netdev->features |= NETIF_F_HW_CSUM;
-		else
-			netdev->features &= ~NETIF_F_HW_CSUM;
+static int
+e1000_get_stats_count(struct net_device *dev)
+{
+	return E1000_STATS_LEN;
+}
 
-		return 0;
-	}
-	case ETHTOOL_GSG: {
-		struct ethtool_value edata = { ETHTOOL_GSG };
+static void
+e1000_get_ethtool_stats(struct net_device *netdev,
+			struct ethtool_stats *stats, u64 *data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	int i;
 
-		edata.data =
-			(netdev->features & NETIF_F_SG) != 0;
-		if (copy_to_user(addr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
+	e1000_update_stats(adapter);
+	for(i = 0; i < E1000_STATS_LEN; i++) {
+		char *p = (char *) adapter + e1000_gstrings_stats[i].stat_offset;
+		data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) 
+			? *(uint64_t *)p : *(uint32_t *)p;
 	}
-	case ETHTOOL_SSG: {
-		struct ethtool_value edata;
-
-		if (copy_from_user(&edata, addr, sizeof(edata)))
-			return -EFAULT;
-
-		if (edata.data)
-			netdev->features |= NETIF_F_SG;
-		else
-			netdev->features &= ~NETIF_F_SG;
+}
 
-		return 0;
-	}
-#ifdef NETIF_F_TSO
-	case ETHTOOL_GTSO: {
-		struct ethtool_value edata = { ETHTOOL_GTSO };
-
-		edata.data = (netdev->features & NETIF_F_TSO) != 0;
-		if (copy_to_user(addr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_STSO: {
-		struct ethtool_value edata;
+static void
+e1000_get_strings(struct net_device *netdev, u32 string_set, u8 *data)
+{
+	int i;
 
-		if (copy_from_user(&edata, addr, sizeof(edata)))
-			return -EFAULT;
+	switch(string_set) {
+	case ETH_SS_TEST:
+		memcpy(data, e1000_gstrings_test, E1000_TEST_LEN * ETH_GSTRING_LEN);
+		break;
 
-		if ((adapter->hw.mac_type < e1000_82544) ||
-		    (adapter->hw.mac_type == e1000_82547)) {
-			if (edata.data != 0)
-				return -EINVAL;
-			return 0;
+	case ETH_SS_STATS:
+		for(i=0; i < E1000_STATS_LEN; i++) {
+			memcpy(data + i * ETH_GSTRING_LEN,
+			       e1000_gstrings_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
 		}
-
-		if (edata.data)
-			netdev->features |= NETIF_F_TSO;
-		else
-			netdev->features &= ~NETIF_F_TSO;
-
-		return 0;
-	}
-#endif
-	default:
-		return -EOPNOTSUPP;
+		break;
 	}
 }
 
 
+struct ethtool_ops e1000_ethtool_ops = {
+	.get_settings		= e1000_get_settings,
+	.set_settings		= e1000_set_settings,
+	.get_drvinfo		= e1000_get_drvinfo,
+	.get_regs_len		= e1000_get_regs_len,
+	.get_regs		= e1000_get_regs,
+	.get_wol		= e1000_get_wol,
+	.set_wol		= e1000_set_wol,
+	.nway_reset		= e1000_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_eeprom_len		= e1000_get_eeprom_len,
+	.get_eeprom		= e1000_get_eeprom,
+	.set_eeprom		= e1000_set_eeprom,
+	.get_ringparam		= e1000_get_ringparam,
+	.set_ringparam		= e1000_set_ringparam,
+	.get_pauseparam		= e1000_get_pauseparam,
+	.set_pauseparam		= e1000_set_pauseparam,
+	.get_rx_csum		= e1000_get_rx_csum,
+	.set_rx_csum		= e1000_set_rx_csum,
+	.get_tx_csum		= e1000_get_tx_csum,
+	.set_tx_csum		= e1000_set_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= e1000_set_tso,
+	.self_test_count	= e1000_diag_test_count,
+	.self_test		= e1000_diag_test,
+	.get_strings		= e1000_get_strings,
+	.phys_id		= e1000_phys_id,
+	.get_stats_count	= e1000_get_stats_count,
+	.get_ethtool_stats	= e1000_get_ethtool_stats,
+};
--- diff/drivers/net/e1000/e1000_main.c	2004-05-19 22:11:57.000000000 +0100
+++ source/drivers/net/e1000/e1000_main.c	2004-05-27 18:34:17.000000000 +0100
@@ -167,9 +167,9 @@
 static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter);
 #endif
 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 int e1000_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+extern struct ethtool_ops e1000_ethtool_ops;
 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,
@@ -206,7 +206,6 @@
 /* Exported from other modules */
 
 extern void e1000_check_options(struct e1000_adapter *adapter);
-extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
 
 static struct pci_driver e1000_driver = {
 	.name     = e1000_driver_name,
@@ -445,7 +444,8 @@
 	netdev->set_multicast_list = &e1000_set_multi;
 	netdev->set_mac_address = &e1000_set_mac;
 	netdev->change_mtu = &e1000_change_mtu;
-	netdev->do_ioctl = &e1000_ioctl;
+	netdev->do_ioctl = &e1000_do_ioctl;
+	SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
 	netdev->tx_timeout = &e1000_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
 #ifdef CONFIG_E1000_NAPI
@@ -2498,37 +2498,16 @@
 		adapter->smartspeed = 0;
 }
 
-/**
- * e1000_ioctl -
- * @netdev:
- * @ifreq:
- * @cmd:
- **/
-
-static int
-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:
-		return -EOPNOTSUPP;
-	}
-}
 
 /**
- * e1000_mii_ioctl -
+ * e1000_do_ioctl -
  * @netdev:
  * @ifreq:
  * @cmd:
  **/
 
 static int
-e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+e1000_do_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;
--- diff/drivers/net/epic100.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/epic100.c	2004-05-27 18:34:17.000000000 +0100
@@ -77,8 +77,6 @@
    These may be modified when a driver module is loaded.*/
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 32;
 
 /* Used to pass the full-duplex flag, etc. */
 #define MAX_UNITS 8		/* More are supported, limit only on options */
@@ -96,9 +94,9 @@
    Making the Tx ring too large decreases the effectiveness of channel
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE	16
-#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
-#define RX_RING_SIZE	32
+#define TX_RING_SIZE	256
+#define TX_QUEUE_LEN	240		/* Limit ring entries actually used.  */
+#define RX_RING_SIZE	256
 #define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct epic_tx_desc)
 #define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct epic_rx_desc)
 
@@ -155,12 +153,10 @@
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(debug, "i");
-MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)");
-MODULE_PARM_DESC(max_interrupt_work, "EPIC/100 maximum events handled per interrupt");
 MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex");
 MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)");
@@ -292,6 +288,12 @@
 	StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80,
 };
 
+#define EpicRemoved	0xffffffff	/* Chip failed or removed (CardBus) */
+
+#define EpicNapiEvent	(TxEmpty | TxDone | \
+			 RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull)
+#define EpicNormalEvent	(0x0000ffff & ~EpicNapiEvent)
+
 static u16 media2miictl[16] = {
 	0, 0x0C00, 0x0C00, 0x2000,  0x0100, 0x2100, 0, 0,
 	0, 0, 0, 0,  0, 0, 0, 0 };
@@ -330,9 +332,12 @@
 
 	/* Ring pointers. */
 	spinlock_t lock;				/* Group with Tx control cache line. */
+	spinlock_t napi_lock;
+	unsigned int reschedule_in_poll;
 	unsigned int cur_tx, dirty_tx;
 
 	unsigned int cur_rx, dirty_rx;
+	u32 irq_mask;
 	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
 
 	struct pci_dev *pci_dev;			/* PCI bus location. */
@@ -359,7 +364,8 @@
 static void epic_tx_timeout(struct net_device *dev);
 static void epic_init_ring(struct net_device *dev);
 static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int epic_rx(struct net_device *dev);
+static int epic_rx(struct net_device *dev, int budget);
+static int epic_poll(struct net_device *dev, int *budget);
 static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static struct ethtool_ops netdev_ethtool_ops;
@@ -378,7 +384,7 @@
 	int irq;
 	struct net_device *dev;
 	struct epic_private *ep;
-	int i, option = 0, duplex = 0;
+	int i, ret, option = 0, duplex = 0;
 	void *ring_space;
 	dma_addr_t ring_dma;
 
@@ -392,29 +398,33 @@
 	
 	card_idx++;
 	
-	i = pci_enable_device(pdev);
-	if (i)
-		return i;
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto out;
 	irq = pdev->irq;
 
 	if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
 		printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_out_disable;
 	}
 	
 	pci_set_master(pdev);
 
+	ret = pci_request_regions(pdev, DRV_NAME);
+	if (ret < 0)
+		goto err_out_disable;
+
+	ret = -ENOMEM;
+
 	dev = alloc_etherdev(sizeof (*ep));
 	if (!dev) {
 		printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
-		return -ENOMEM;
+		goto err_out_free_res;
 	}
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	if (pci_request_regions(pdev, DRV_NAME))
-		goto err_out_free_netdev;
-
 #ifdef USE_IO_OPS
 	ioaddr = pci_resource_start (pdev, 0);
 #else
@@ -422,7 +432,7 @@
 	ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
 	if (!ioaddr) {
 		printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
-		goto err_out_free_res;
+		goto err_out_free_netdev;
 	}
 #endif
 
@@ -459,7 +469,9 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
-	spin_lock_init (&ep->lock);
+	spin_lock_init(&ep->lock);
+	spin_lock_init(&ep->napi_lock);
+	ep->reschedule_in_poll = 0;
 
 	/* Bring the chip out of low-power mode. */
 	outl(0x4200, ioaddr + GENCTL);
@@ -489,6 +501,9 @@
 	ep->pci_dev = pdev;
 	ep->chip_id = chip_idx;
 	ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
+	ep->irq_mask = 
+		(ep->chip_flags & TYPE2_INTR ?  PCIBusErr175 : PCIBusErr170)
+		 | CntFull | TxUnderrun | EpicNapiEvent;
 
 	/* Find the connected MII xcvrs.
 	   Doing this in open() would allow detecting external xcvrs later, but
@@ -543,10 +558,12 @@
 	dev->ethtool_ops = &netdev_ethtool_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->tx_timeout = &epic_tx_timeout;
+	dev->poll = epic_poll;
+	dev->weight = 64;
 
-	i = register_netdev(dev);
-	if (i)
-		goto err_out_unmap_tx;
+	ret = register_netdev(dev);
+	if (ret < 0)
+		goto err_out_unmap_rx;
 
 	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
 		   dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq);
@@ -554,19 +571,24 @@
 		printk("%2.2x:", dev->dev_addr[i]);
 	printk("%2.2x.\n", dev->dev_addr[i]);
 
-	return 0;
+out:
+	return ret;
 
+err_out_unmap_rx:
+	pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
 err_out_unmap_tx:
 	pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
 err_out_iounmap:
 #ifndef USE_IO_OPS
 	iounmap(ioaddr);
-err_out_free_res:
-#endif
-	pci_release_regions(pdev);
 err_out_free_netdev:
+#endif
 	free_netdev(dev);
-	return -ENODEV;
+err_out_free_res:
+	pci_release_regions(pdev);
+err_out_disable:
+	pci_disable_device(pdev);
+	goto out;
 }
 
 /* Serial EEPROM section. */
@@ -592,6 +614,38 @@
 #define EE_READ256_CMD	(6 << 8)
 #define EE_ERASE_CMD	(7 << 6)
 
+static void epic_disable_int(struct net_device *dev, struct epic_private *ep)
+{
+	long ioaddr = dev->base_addr;
+
+	outl(0x00000000, ioaddr + INTMASK);
+}
+
+static inline void __epic_pci_commit(long ioaddr)
+{
+#ifndef USE_IO_OPS
+	inl(ioaddr + INTMASK);
+#endif
+}
+
+static inline void epic_napi_irq_off(struct net_device *dev,
+				     struct epic_private *ep)
+{
+	long ioaddr = dev->base_addr;
+
+	outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK);
+	__epic_pci_commit(ioaddr);
+}
+
+static inline void epic_napi_irq_on(struct net_device *dev,
+				    struct epic_private *ep)
+{
+	long ioaddr = dev->base_addr;
+
+	/* No need to commit possible posted write */
+	outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK);
+}
+
 static int __devinit read_eeprom(long ioaddr, int location)
 {
 	int i;
@@ -752,9 +806,8 @@
 
 	/* Enable interrupts by setting the interrupt mask. */
 	outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
-		 | CntFull | TxUnderrun | TxDone | TxEmpty
-		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
-		 ioaddr + INTMASK);
+		 | CntFull | TxUnderrun 
+		 | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
 
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
@@ -795,7 +848,7 @@
 	}
 
 	/* Remove the packets on the Rx queue. */
-	epic_rx(dev);
+	epic_rx(dev, RX_RING_SIZE);
 }
 
 static void epic_restart(struct net_device *dev)
@@ -841,9 +894,9 @@
 
 	/* Enable interrupts by setting the interrupt mask. */
 	outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
-		 | CntFull | TxUnderrun | TxDone | TxEmpty
-		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
-		 ioaddr + INTMASK);
+		 | CntFull | TxUnderrun
+		 | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
+
 	printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
 		   " interrupt %4.4x.\n",
 		   dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL),
@@ -929,7 +982,6 @@
 	int i;
 
 	ep->tx_full = 0;
-	ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 	ep->dirty_tx = ep->cur_tx = 0;
 	ep->cur_rx = ep->dirty_rx = 0;
 	ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
@@ -1029,6 +1081,76 @@
 	return 0;
 }
 
+static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
+			  int status)
+{
+	struct net_device_stats *stats = &ep->stats;
+
+#ifndef final_version
+	/* There was an major error, log it. */
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+		       dev->name, status);
+#endif
+	stats->tx_errors++;
+	if (status & 0x1050)
+		stats->tx_aborted_errors++;
+	if (status & 0x0008)
+		stats->tx_carrier_errors++;
+	if (status & 0x0040)
+		stats->tx_window_errors++;
+	if (status & 0x0010)
+		stats->tx_fifo_errors++;
+}
+
+static void epic_tx(struct net_device *dev, struct epic_private *ep)
+{
+	unsigned int dirty_tx, cur_tx;
+
+	/*
+	 * Note: if this lock becomes a problem we can narrow the locked
+	 * region at the cost of occasionally grabbing the lock more times.
+	 */
+	cur_tx = ep->cur_tx;
+	for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) {
+		struct sk_buff *skb;
+		int entry = dirty_tx % TX_RING_SIZE;
+		int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
+
+		if (txstatus & DescOwn)
+			break;	/* It still hasn't been Txed */
+
+		if (likely(txstatus & 0x0001)) {
+			ep->stats.collisions += (txstatus >> 8) & 15;
+			ep->stats.tx_packets++;
+			ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
+		} else
+			epic_tx_error(dev, ep, txstatus);
+
+		/* Free the original skb. */
+		skb = ep->tx_skbuff[entry];
+		pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, 
+				 skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_irq(skb);
+		ep->tx_skbuff[entry] = 0;
+	}
+
+#ifndef final_version
+	if (cur_tx - dirty_tx > TX_RING_SIZE) {
+		printk(KERN_WARNING
+		       "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+		       dev->name, dirty_tx, cur_tx, ep->tx_full);
+		dirty_tx += TX_RING_SIZE;
+	}
+#endif
+	ep->dirty_tx = dirty_tx;
+	if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
+		/* The ring is no longer full, allow new TX entries. */
+		ep->tx_full = 0;
+		netif_wake_queue(dev);
+	}
+}
+
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
@@ -1036,135 +1158,71 @@
 	struct net_device *dev = dev_instance;
 	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
-	int status, boguscnt = max_interrupt_work;
 	unsigned int handled = 0;
+	int status;
 
-	do {
-		status = inl(ioaddr + INTSTAT);
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		outl(status & 0x00007fff, ioaddr + INTSTAT);
-
-		if (debug > 4)
-			printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "
-				   "intstat=%#8.8x.\n",
-				   dev->name, status, (int)inl(ioaddr + INTSTAT));
-
-		if ((status & IntrSummary) == 0)
-			break;
-		handled = 1;
+	status = inl(ioaddr + INTSTAT);
+	/* Acknowledge all of the current interrupt sources ASAP. */
+	outl(status & EpicNormalEvent, ioaddr + INTSTAT);
 
-		if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow))
-			epic_rx(dev);
+	if (debug > 4) {
+		printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "
+				   "intstat=%#8.8x.\n", dev->name, status,
+				   (int)inl(ioaddr + INTSTAT));
+	}
 
-		if (status & (TxEmpty | TxDone)) {
-			unsigned int dirty_tx, cur_tx;
+	if ((status & IntrSummary) == 0)
+		goto out;
 
-			/* Note: if this lock becomes a problem we can narrow the locked
-			   region at the cost of occasionally grabbing the lock more
-			   times. */
-			spin_lock(&ep->lock);
-			cur_tx = ep->cur_tx;
-			dirty_tx = ep->dirty_tx;
-			for (; cur_tx - dirty_tx > 0; dirty_tx++) {
-				struct sk_buff *skb;
-				int entry = dirty_tx % TX_RING_SIZE;
-				int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
+	handled = 1;
 
-				if (txstatus & DescOwn)
-					break;			/* It still hasn't been Txed */
+	if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
+		spin_lock(&ep->napi_lock);
+		if (netif_rx_schedule_prep(dev)) {
+			epic_napi_irq_off(dev, ep);
+			__netif_rx_schedule(dev);
+		} else
+			ep->reschedule_in_poll++;
+		spin_unlock(&ep->napi_lock);
+	}
+	status &= ~EpicNapiEvent;
 
-				if ( ! (txstatus & 0x0001)) {
-					/* There was an major error, log it. */
-#ifndef final_version
-					if (debug > 1)
-						printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-							   dev->name, txstatus);
-#endif
-					ep->stats.tx_errors++;
-					if (txstatus & 0x1050) ep->stats.tx_aborted_errors++;
-					if (txstatus & 0x0008) ep->stats.tx_carrier_errors++;
-					if (txstatus & 0x0040) ep->stats.tx_window_errors++;
-					if (txstatus & 0x0010) ep->stats.tx_fifo_errors++;
-				} else {
-					ep->stats.collisions += (txstatus >> 8) & 15;
-					ep->stats.tx_packets++;
-					ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
-				}
-
-				/* Free the original skb. */
-				skb = ep->tx_skbuff[entry];
-				pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, 
-						 skb->len, PCI_DMA_TODEVICE);
-				dev_kfree_skb_irq(skb);
-				ep->tx_skbuff[entry] = 0;
-			}
+	/* Check uncommon events all at once. */
+	if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) {
+		if (status == EpicRemoved)
+			goto out;
 
-#ifndef final_version
-			if (cur_tx - dirty_tx > TX_RING_SIZE) {
-				printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dev->name, dirty_tx, cur_tx, ep->tx_full);
-				dirty_tx += TX_RING_SIZE;
-			}
-#endif
-			ep->dirty_tx = dirty_tx;
-			if (ep->tx_full
-				&& cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
-				/* The ring is no longer full, allow new TX entries. */
-				ep->tx_full = 0;
-				spin_unlock(&ep->lock);
-				netif_wake_queue(dev);
-			} else
-				spin_unlock(&ep->lock);
-		}
+		/* Always update the error counts to avoid overhead later. */
+		ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+		ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+		ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
 
-		/* Check uncommon events all at once. */
-		if (status & (CntFull | TxUnderrun | RxOverflow | RxFull |
-					  PCIBusErr170 | PCIBusErr175)) {
-			if (status == 0xffffffff) /* Chip failed or removed (CardBus). */
-				break;
-			/* Always update the error counts to avoid overhead later. */
-			ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-			ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-			ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
-
-			if (status & TxUnderrun) { /* Tx FIFO underflow. */
-				ep->stats.tx_fifo_errors++;
-				outl(ep->tx_threshold += 128, ioaddr + TxThresh);
-				/* Restart the transmit process. */
-				outl(RestartTx, ioaddr + COMMAND);
-			}
-			if (status & RxOverflow) {		/* Missed a Rx frame. */
-				ep->stats.rx_errors++;
-			}
-			if (status & (RxOverflow | RxFull))
-				outw(RxQueued, ioaddr + COMMAND);
-			if (status & PCIBusErr170) {
-				printk(KERN_ERR "%s: PCI Bus Error!  EPIC status %4.4x.\n",
-					   dev->name, status);
-				epic_pause(dev);
-				epic_restart(dev);
-			}
-			/* Clear all error sources. */
-			outl(status & 0x7f18, ioaddr + INTSTAT);
+		if (status & TxUnderrun) { /* Tx FIFO underflow. */
+			ep->stats.tx_fifo_errors++;
+			outl(ep->tx_threshold += 128, ioaddr + TxThresh);
+			/* Restart the transmit process. */
+			outl(RestartTx, ioaddr + COMMAND);
 		}
-		if (--boguscnt < 0) {
-			printk(KERN_ERR "%s: Too much work at interrupt, "
-				   "IntrStatus=0x%8.8x.\n",
-				   dev->name, status);
-			/* Clear all interrupt sources. */
-			outl(0x0001ffff, ioaddr + INTSTAT);
-			break;
+		if (status & PCIBusErr170) {
+			printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n",
+					 dev->name, status);
+			epic_pause(dev);
+			epic_restart(dev);
 		}
-	} while (1);
+		/* Clear all error sources. */
+		outl(status & 0x7f18, ioaddr + INTSTAT);
+	}
 
-	if (debug > 3)
-		printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n",
-			   dev->name, status);
+out:
+	if (debug > 3) {
+		printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n",
+				   dev->name, status);
+	}
 
 	return IRQ_RETVAL(handled);
 }
 
-static int epic_rx(struct net_device *dev)
+static int epic_rx(struct net_device *dev, int budget)
 {
 	struct epic_private *ep = dev->priv;
 	int entry = ep->cur_rx % RX_RING_SIZE;
@@ -1174,6 +1232,10 @@
 	if (debug > 4)
 		printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,
 			   ep->rx_ring[entry].rxstatus);
+
+	if (rx_work_limit > budget)
+		rx_work_limit = budget;
+
 	/* If we own the next entry, it's a new packet. Send it up. */
 	while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) {
 		int status = le32_to_cpu(ep->rx_ring[entry].rxstatus);
@@ -1215,13 +1277,8 @@
 							    ep->rx_ring[entry].bufaddr,
 							    ep->rx_buf_sz,
 							    PCI_DMA_FROMDEVICE);
-#if 1 /* HAS_IP_COPYSUM */
 				eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len), ep->rx_skbuff[entry]->tail,
-					   pkt_len);
-#endif
 				pci_dma_sync_single_for_device(ep->pci_dev,
 							       ep->rx_ring[entry].bufaddr,
 							       ep->rx_buf_sz,
@@ -1234,7 +1291,7 @@
 				ep->rx_skbuff[entry] = NULL;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
+			netif_receive_skb(skb);
 			dev->last_rx = jiffies;
 			ep->stats.rx_packets++;
 			ep->stats.rx_bytes += pkt_len;
@@ -1262,6 +1319,65 @@
 	return work_done;
 }
 
+static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
+{
+	long ioaddr = dev->base_addr;
+	int status;
+
+	status = inl(ioaddr + INTSTAT);
+
+	if (status == EpicRemoved)
+		return;
+	if (status & RxOverflow) 	/* Missed a Rx frame. */
+		ep->stats.rx_errors++;
+	if (status & (RxOverflow | RxFull))
+		outw(RxQueued, ioaddr + COMMAND);
+}
+
+static int epic_poll(struct net_device *dev, int *budget)
+{
+	struct epic_private *ep = dev->priv;
+	int work_done, orig_budget;
+	long ioaddr = dev->base_addr;
+
+	orig_budget = (*budget > dev->quota) ? dev->quota : *budget;
+
+rx_action:
+
+	epic_tx(dev, ep);
+
+	work_done = epic_rx(dev, *budget);
+
+	epic_rx_err(dev, ep);
+
+	*budget -= work_done;
+	dev->quota -= work_done;
+
+	if (netif_running(dev) && (work_done < orig_budget)) {
+		unsigned long flags;
+		int more;
+
+		/* A bit baroque but it avoids a (space hungry) spin_unlock */
+
+		spin_lock_irqsave(&ep->napi_lock, flags);
+
+		more = ep->reschedule_in_poll;
+		if (!more) {
+			__netif_rx_complete(dev);
+			outl(EpicNapiEvent, ioaddr + INTSTAT);
+			epic_napi_irq_on(dev, ep);
+		} else
+			ep->reschedule_in_poll--;
+
+		spin_unlock_irqrestore(&ep->napi_lock, flags);
+
+		if (more)
+			goto rx_action;
+	}
+
+	return (work_done >= orig_budget);
+}
+
 static int epic_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
@@ -1276,9 +1392,13 @@
 			   dev->name, (int)inl(ioaddr + INTSTAT));
 
 	del_timer_sync(&ep->timer);
-	epic_pause(dev);
+
+	epic_disable_int(dev, ep);
+
 	free_irq(dev->irq, dev);
 
+	epic_pause(dev);
+
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		skb = ep->rx_skbuff[i];
@@ -1476,6 +1596,7 @@
 #endif
 	pci_release_regions(pdev);
 	free_netdev(dev);
+	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 	/* pci_power_off(pdev, -1); */
 }
--- diff/drivers/net/fealnx.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/net/fealnx.c	2004-05-27 18:34:17.000000000 +0100
@@ -858,12 +858,17 @@
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
+	int i;
 
 	writel(0x00000001, ioaddr + BCR);	/* Reset */
 
 	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
 		return -EAGAIN;
 
+	for (i = 0; i < 3; i++)
+		writew(((unsigned short*)dev->dev_addr)[i],
+				ioaddr + PAR0 + i*2);
+
 	init_ring(dev);
 
 	writel(np->rx_ring_dma, ioaddr + RXLBA);
--- diff/drivers/net/lasi_82596.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/lasi_82596.c	2004-05-27 18:34:17.000000000 +0100
@@ -87,7 +87,6 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/pdc.h>
 #include <asm/cache.h>
--- diff/drivers/net/macsonic.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/macsonic.c	2004-05-27 18:34:17.000000000 +0100
@@ -53,7 +53,6 @@
 #include <asm/macintosh.h>
 #include <asm/macints.h>
 #include <asm/mac_via.h>
-#include <asm/pgalloc.h>
 
 #define SREGS_PAD(n)    u16 n;
 
--- diff/drivers/net/natsemi.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/natsemi.c	2004-05-27 18:34:17.000000000 +0100
@@ -1798,14 +1798,9 @@
 					np->rx_dma[entry],
 					buflen,
 					PCI_DMA_FROMDEVICE);
-#if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb,
 					np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len),
-					np->rx_skbuff[entry]->tail, pkt_len);
-#endif
 				pci_dma_sync_single_for_device(np->pci_dev,
 					np->rx_dma[entry],
 					buflen,
--- diff/drivers/net/ne-h8300.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/net/ne-h8300.c	2004-05-27 18:34:17.000000000 +0100
@@ -260,8 +260,8 @@
 	bus_width &= 1 << ((ioaddr >> 21) & 7);
 	ei_status.word16 = (bus_width == 0); /* temporary setting */
 	for(i = 0; i < 16 /*sizeof(SA_prom)*/; i++) {
-		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
-		inb(ioaddr + NE_DATAPORT); /* dummy read */
+		SA_prom[i] = inb_p(ioaddr + NE_DATAPORT);
+		inb_p(ioaddr + NE_DATAPORT); /* dummy read */
 	}
 
 	start_page = NESM_START_PG;
@@ -590,7 +590,7 @@
 
 
 #ifdef MODULE
-#define MAX_NE_CARDS	4	/* Max number of NE cards per module */
+#define MAX_NE_CARDS	1	/* 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];
@@ -599,7 +599,7 @@
 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_DESC(io, "I/O base address(es),required");
+MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s)");
 MODULE_DESCRIPTION("H8/300 NE2000 Ethernet driver");
 MODULE_LICENSE("GPL");
@@ -612,26 +612,35 @@
 int init_module(void)
 {
 	int this_dev, found = 0;
+	int err;
 
 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
 		struct net_device *dev = alloc_ei_netdev();
 		if (!dev)
 			break;
-		dev->irq = irq[this_dev];
-		dev->mem_end = bad[this_dev];
-		dev->base_addr = io[this_dev];
-		if (do_ne_probe(dev) == 0) {
-			if (register_netdev(dev) == 0) {
-				dev_ne[found++] = dev;
-				continue;
+		if (io[this_dev]) {
+			dev->irq = irq[this_dev];
+			dev->mem_end = bad[this_dev];
+			dev->base_addr = io[this_dev];
+		} else {
+			dev->base_addr = h8300_ne_base[this_dev];
+			dev->irq = h8300_ne_irq[this_dev];
+		}
+		err = init_reg_offset(dev, dev->base_addr);
+		if (!err) {
+			if (do_ne_probe(dev) == 0) {
+				if (register_netdev(dev) == 0) {
+					dev_ne[found++] = dev;
+					continue;
+				}
+				cleanup_card(dev);
 			}
-			cleanup_card(dev);
 		}
 		free_netdev(dev);
 		if (found)
 			break;
 		if (io[this_dev] != 0)
-			printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
+			printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", dev->base_addr);
 		else
 			printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n");
 		return -ENXIO;
--- diff/drivers/net/r8169.c	2004-05-27 13:41:18.000000000 +0100
+++ source/drivers/net/r8169.c	2004-05-27 18:34:17.000000000 +0100
@@ -7,7 +7,7 @@
  Feb  4 2002	- created initially by ShuChen <shuchen@realtek.com.tw>.
  May 20 2002	- Add link status force-mode and TBI mode support.
 =========================================================================
-  1. The media can be forced in 5 modes.
+  1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes.
 	 Command: 'insmod r8169 media = SET_MEDIA'
 	 Ex:	  'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
 	
@@ -41,6 +41,7 @@
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
 #include <linux/crc32.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
@@ -64,6 +65,14 @@
 #define dprintk(fmt, args...)	do {} while (0)
 #endif /* RTL8169_DEBUG */
 
+#ifdef CONFIG_R8169_NAPI
+#define rtl8169_rx_skb			netif_receive_skb
+#define rtl8169_rx_quota(count, quota)	min(count, quota)
+#else
+#define rtl8169_rx_skb			netif_rx
+#define rtl8169_rx_quota(count, quota)	count
+#endif
+
 /* media options */
 #define MAX_UNITS 8
 static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
@@ -90,15 +99,16 @@
 #define RxPacketMaxSize	0x0800	/* Maximum size supported is 16K-1 */
 #define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
 
+#define R8169_NAPI_WEIGHT	64
 #define NUM_TX_DESC	64	/* Number of Tx descriptor registers */
-#define NUM_RX_DESC	64	/* Number of Rx descriptor registers */
+#define NUM_RX_DESC	256	/* Number of Rx descriptor registers */
 #define RX_BUF_SIZE	1536	/* Rx Buffer size */
 #define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
 #define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
 
 #define RTL_MIN_IO_SIZE 0x80
 #define RTL8169_TX_TIMEOUT	(6*HZ)
-#define RTL8169_PHY_TIMEOUT	(HZ) 
+#define RTL8169_PHY_TIMEOUT	(10*HZ)
 
 /* write/read MMIO register */
 #define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
@@ -194,7 +204,7 @@
 	SWInt = 0x0100,
 	TxDescUnavail = 0x80,
 	RxFIFOOver = 0x40,
-	RxUnderrun = 0x20,
+	LinkChg = 0x20,
 	RxOverflow = 0x10,
 	TxErr = 0x08,
 	TxOK = 0x04,
@@ -233,6 +243,14 @@
 	TxInterFrameGapShift = 24,
 	TxDMAShift = 8,	/* DMA burst value (0-7) is shift this many bits */
 
+	/* TBICSR p.28 */
+	TBIReset	= 0x80000000,
+	TBILoopback	= 0x40000000,
+	TBINwEnable	= 0x20000000,
+	TBINwRestart	= 0x10000000,
+	TBILinkOk	= 0x02000000,
+	TBINwComplete	= 0x01000000,
+
 	/* CPlusCmd p.31 */
 	RxVlan		= (1 << 6),
 	RxChkSum	= (1 << 5),
@@ -306,10 +324,10 @@
 };
 
 struct rtl8169_private {
-	void *mmio_addr;	/* memory map physical address */
+	void *mmio_addr;		/* memory map physical address */
 	struct pci_dev *pci_dev;	/* Index of PCI device  */
 	struct net_device_stats stats;	/* statistics of net device */
-	spinlock_t lock;	/* spin lock flag */
+	spinlock_t lock;		/* spin lock flag */
 	int chipset;
 	int mac_version;
 	int phy_version;
@@ -317,15 +335,25 @@
 	u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
 	u32 dirty_rx;
 	u32 dirty_tx;
-	struct TxDesc *TxDescArray;	/* Index of 256-alignment Tx Descriptor buffer */
-	struct RxDesc *RxDescArray;	/* Index of 256-alignment Rx Descriptor buffer */
+	struct TxDesc *TxDescArray;	/* 256-aligned Tx descriptor ring */
+	struct RxDesc *RxDescArray;	/* 256-aligned Rx descriptor ring */
 	dma_addr_t TxPhyAddr;
 	dma_addr_t RxPhyAddr;
 	struct sk_buff *Rx_skbuff[NUM_RX_DESC];	/* Rx data buffers */
-	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Index of Transmit data buffer */
+	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Tx data buffers */
 	struct timer_list timer;
-	unsigned long phy_link_down_cnt;
+	unsigned int phy_tried_renegotiate;	/* renegotiation hack */
 	u16 cp_cmd;
+	u16 intr_mask;
+	int phy_auto_nego_reg;
+	int phy_1000_ctrl_reg;
+
+	int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
+	void (*get_settings)(struct net_device *, struct ethtool_cmd *);
+	void (*phy_reset_enable)(void *);
+	unsigned int (*phy_reset_pending)(void *);
+	unsigned int (*link_ok)(void *);
+	void (*andy_s_phy_renegotiation_hack)(struct rtl8169_private *);
 };
 
 MODULE_AUTHOR("Realtek");
@@ -344,9 +372,14 @@
 static void rtl8169_set_rx_mode(struct net_device *dev);
 static void rtl8169_tx_timeout(struct net_device *dev);
 static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);
+#ifdef CONFIG_R8169_NAPI
+static int rtl8169_poll(struct net_device *dev, int *budget);
+#endif
 
 static const u16 rtl8169_intr_mask =
-    RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
+	LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
+static const u16 rtl8169_napi_event =
+	RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr;
 static const unsigned int rtl8169_rx_config =
     (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
 
@@ -364,11 +397,9 @@
 
 	for (i = 2000; i > 0; i--) {
 		// Check if the RTL8169 has completed writing to the specified MII register
-		if (!(RTL_R32(PHYAR) & 0x80000000)) {
+		if (!(RTL_R32(PHYAR) & 0x80000000)) 
 			break;
-		} else {
-			udelay(100);
-		}
+		udelay(100);
 	}
 }
 
@@ -390,18 +421,277 @@
 	return value;
 }
 
+static unsigned int rtl8169_tbi_reset_pending(void *ioaddr)
+{
+	return RTL_R32(TBICSR) & TBIReset;
+}
+
+static unsigned int rtl8169_xmii_reset_pending(void *ioaddr)
+{
+	return mdio_read(ioaddr, 0) & 0x8000;
+}
+
+static unsigned int rtl8169_tbi_link_ok(void *ioaddr)
+{
+	return RTL_R32(TBICSR) & TBILinkOk;
+}
+
+static unsigned int rtl8169_xmii_link_ok(void *ioaddr)
+{
+	return RTL_R8(PHYstatus) & LinkStatus;
+}
+
+static void rtl8169_tbi_reset_enable(void *ioaddr)
+{
+	RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
+}
+
+static void rtl8169_xmii_reset_enable(void *ioaddr)
+{
+	unsigned int val;
+
+	val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff;
+	mdio_write(ioaddr, PHY_CTRL_REG, val);
+}
+
+static void rtl8169_xmii_renegotiation_hack(struct rtl8169_private *tp)
+{
+	void *ioaddr = tp->mmio_addr;
+
+	if (!tp->phy_tried_renegotiate && !(RTL_R8(PHYstatus) & _1000bpsF)) {
+		mdio_write(ioaddr, PHY_CTRL_REG,
+			   BMCR_ANRESTART | BMCR_ANENABLE);
+		tp->phy_tried_renegotiate++;
+	}
+}
+
+static void rtl8169_check_link_status(struct net_device *dev,
+				      struct rtl8169_private *tp, void *ioaddr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+	if (tp->link_ok(ioaddr)) {
+		netif_carrier_on(dev);
+		printk(KERN_INFO PFX "%s: link up\n", dev->name);
+	} else {
+		netif_carrier_off(dev);
+		mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
+	}
+	spin_unlock_irqrestore(&tp->lock, flags);
+}
+
+static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
+{
+	struct {
+		u16 speed;
+		u8 duplex;
+		u8 autoneg;
+		u8 media;
+	} link_settings[] = {
+		{ SPEED_10,	DUPLEX_HALF, AUTONEG_DISABLE,	_10_Half },
+		{ SPEED_10,	DUPLEX_FULL, AUTONEG_DISABLE,	_10_Full },
+		{ SPEED_100,	DUPLEX_HALF, AUTONEG_DISABLE,	_100_Half },
+		{ SPEED_100,	DUPLEX_FULL, AUTONEG_DISABLE,	_100_Full },
+		{ SPEED_1000,	DUPLEX_FULL, AUTONEG_DISABLE,	_1000_Full },
+		/* Make TBI happy */
+		{ SPEED_1000,	DUPLEX_FULL, AUTONEG_ENABLE,	0xff }
+	}, *p;
+	unsigned char option;
+
+	option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff;
+
+	if ((option != 0xff) && !idx)
+		printk(KERN_WARNING PFX "media option is deprecated.\n");
+
+	for (p = link_settings; p->media != 0xff; p++) {
+		if (p->media == option)
+			break;
+	}
+	*autoneg = p->autoneg;
+	*speed = p->speed;
+	*duplex = p->duplex;
+}
+
 static void rtl8169_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 
 	strcpy(info->driver, RTL8169_DRIVER_NAME);
 	strcpy(info->version, RTL8169_VERSION );
 	strcpy(info->bus_info, pci_name(tp->pci_dev));
 }
 
+static int rtl8169_set_speed_tbi(struct net_device *dev,
+				 u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	int ret = 0;
+	u32 reg;
+
+	reg = RTL_R32(TBICSR);
+	if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
+	    (duplex == DUPLEX_FULL)) {
+		RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
+	} else if (autoneg == AUTONEG_ENABLE)
+		RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
+	else {
+		printk(KERN_WARNING PFX
+		       "%s: incorrect speed setting refused in TBI mode\n",
+		       dev->name);
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+static int rtl8169_set_speed_xmii(struct net_device *dev,
+				  u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	int auto_nego, giga_ctrl;
+
+	auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
+	auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full |
+		       PHY_Cap_100_Half | PHY_Cap_100_Full);
+	giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG);
+	giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null);
+
+	if (autoneg == AUTONEG_ENABLE) {
+		auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full |
+			      PHY_Cap_100_Half | PHY_Cap_100_Full);
+		giga_ctrl |= PHY_Cap_1000_Full;
+	} else {
+		if (speed == SPEED_10)
+			auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full;
+		else if (speed == SPEED_100)
+			auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full;
+		else if (speed == SPEED_1000)
+			giga_ctrl |= PHY_Cap_1000_Full;
+
+		if (duplex == DUPLEX_HALF)
+			auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full);
+	}
+
+	tp->phy_auto_nego_reg = auto_nego;
+	tp->phy_1000_ctrl_reg = giga_ctrl;
+
+	mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego);
+	mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl);
+	mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego |
+					 PHY_Restart_Auto_Nego);
+	return 0;
+}
+
+static int rtl8169_set_speed(struct net_device *dev,
+			     u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	int ret;
+
+	ret = tp->set_speed(dev, autoneg, speed, duplex);
+
+	if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
+		mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
+
+	return ret;
+}
+
+static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&tp->lock, flags);
+	ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex);
+	spin_unlock_irqrestore(&tp->lock, flags);
+
+	return ret;
+}
+
+static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	u32 status;
+
+	cmd->supported =
+		SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE;
+	cmd->port = PORT_FIBRE;
+	cmd->transceiver = XCVR_INTERNAL;
+
+	status = RTL_R32(TBICSR);
+	cmd->advertising = (status & TBINwEnable) ?  ADVERTISED_Autoneg : 0;
+	cmd->autoneg = !!(status & TBINwEnable);
+
+	cmd->speed = SPEED_1000;
+	cmd->duplex = DUPLEX_FULL; /* Always set */
+}
+
+static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	u8 status;
+
+	cmd->supported = SUPPORTED_10baseT_Half |
+			 SUPPORTED_10baseT_Full |
+			 SUPPORTED_100baseT_Half |
+			 SUPPORTED_100baseT_Full |
+			 SUPPORTED_1000baseT_Full |
+			 SUPPORTED_Autoneg |
+		         SUPPORTED_TP;
+
+	cmd->autoneg = 1;
+	cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
+
+	if (tp->phy_auto_nego_reg & PHY_Cap_10_Half)
+		cmd->advertising |= ADVERTISED_10baseT_Half;
+	if (tp->phy_auto_nego_reg & PHY_Cap_10_Full)
+		cmd->advertising |= ADVERTISED_10baseT_Full;
+	if (tp->phy_auto_nego_reg & PHY_Cap_100_Half)
+		cmd->advertising |= ADVERTISED_100baseT_Half;
+	if (tp->phy_auto_nego_reg & PHY_Cap_100_Full)
+		cmd->advertising |= ADVERTISED_100baseT_Full;
+	if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)
+		cmd->advertising |= ADVERTISED_1000baseT_Full;
+
+	status = RTL_R8(PHYstatus);
+
+	if (status & _1000bpsF)
+		cmd->speed = SPEED_1000;
+	else if (status & _100bps)
+		cmd->speed = SPEED_100;
+	else if (status & _10bps)
+		cmd->speed = SPEED_10;
+
+	cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ?
+		      DUPLEX_FULL : DUPLEX_HALF;
+}
+
+static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+
+	tp->get_settings(dev, cmd);
+
+	spin_unlock_irqrestore(&tp->lock, flags);
+	return 0;
+}
+
+
 static struct ethtool_ops rtl8169_ethtool_ops = {
 	.get_drvinfo		= rtl8169_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_settings		= rtl8169_get_settings,
+	.set_settings		= rtl8169_set_settings,
 };
 
 static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum,
@@ -500,7 +790,7 @@
 
 static void rtl8169_hw_phy_config(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	struct {
 		u16 regs[5]; /* Beware of bit-sign propagation */
@@ -566,61 +856,51 @@
 	mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0
 }
 
-static void rtl8169_hw_phy_reset(struct net_device *dev)
-{
-	struct rtl8169_private *tp = dev->priv;
-	void *ioaddr = tp->mmio_addr;
-	int i, val;
-
-	printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name);
-
-	val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff;
-	mdio_write(ioaddr, 0, val);
-
-	for (i = 50; i >= 0; i--) {
-		if (!(mdio_read(ioaddr, 0) & 0x8000))
-			break;
-		udelay(100); /* Gross */
-	}
-
-	if (i < 0) {
-		printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n",
-		       dev->name);
-	}
-}
-
 static void rtl8169_phy_timer(unsigned long __opaque)
 {
 	struct net_device *dev = (struct net_device *)__opaque;
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct timer_list *timer = &tp->timer;
 	void *ioaddr = tp->mmio_addr;
+	unsigned long timeout = RTL8169_PHY_TIMEOUT;
 
 	assert(tp->mac_version > RTL_GIGA_MAC_VER_B);
 	assert(tp->phy_version < RTL_GIGA_PHY_VER_G);
 
-	if (RTL_R8(PHYstatus) & LinkStatus)
-		tp->phy_link_down_cnt = 0;
-	else {
-		tp->phy_link_down_cnt++;
-		if (tp->phy_link_down_cnt >= 12) {
-			int reg;
-
-			// If link on 1000, perform phy reset.
-			reg = mdio_read(ioaddr, PHY_1000_CTRL_REG);
-			if (reg & PHY_Cap_1000_Full) 
-				rtl8169_hw_phy_reset(dev);
+	if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
+		return;
 
-			tp->phy_link_down_cnt = 0;
-		}
+	spin_lock_irq(&tp->lock);
+
+	if (tp->phy_reset_pending(ioaddr)) {
+		/*
+		 * A busy loop could burn quite a few cycles on nowadays CPU.
+		 * Let's delay the execution of the timer for a few ticks.
+		 */
+		timeout = HZ/10;
+		goto out_mod_timer;
 	}
 
-	mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
+	if (tp->link_ok(ioaddr)) {
+		/* Nothing personal here. Simple documentation purpose :o) */
+		if (tp->andy_s_phy_renegotiation_hack)
+			tp->andy_s_phy_renegotiation_hack(tp);
+		goto out_unlock;
+	}
+
+	printk(KERN_WARNING PFX "%s: PHY reset until link up\n", dev->name);
+
+	tp->phy_reset_enable(ioaddr);
+
+out_mod_timer:
+	mod_timer(timer, jiffies + timeout);
+out_unlock:
+	spin_unlock_irq(&tp->lock);
 }
 
 static inline void rtl8169_delete_timer(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct timer_list *timer = &tp->timer;
 
 	if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
@@ -628,21 +908,17 @@
 		return;
 
 	del_timer_sync(timer);
-
-	tp->phy_link_down_cnt = 0;
 }
 
 static inline void rtl8169_request_timer(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct timer_list *timer = &tp->timer;
 
 	if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
 	    (tp->phy_version >= RTL_GIGA_PHY_VER_G))
 		return;
 
-	tp->phy_link_down_cnt = 0;
-
 	init_timer(timer);
 	timer->expires = jiffies + RTL8169_PHY_TIMEOUT;
 	timer->data = (unsigned long)(dev);
@@ -681,7 +957,7 @@
 	// enable device (incl. PCI PM wakeup and hotplug setup)
 	rc = pci_enable_device(pdev);
 	if (rc) {
-		printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name);
+		printk(KERN_ERR PFX "%s: enable failure\n", pdev->slot_name);
 		goto err_out;
 	}
 
@@ -693,7 +969,8 @@
 		pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
 		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
 	} else {
-		printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n");
+		printk(KERN_ERR PFX
+		       "Cannot find PowerManagement capability, aborting.\n");
 		goto err_out_free_res;
 	}
 
@@ -718,7 +995,8 @@
 
 	rc = pci_request_regions(pdev, dev->name);
 	if (rc) {
-		printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name);
+		printk(KERN_ERR PFX "%s: could not request regions.\n",
+		       pdev->slot_name);
 		goto err_out_disable;
 	}
 
@@ -800,8 +1078,9 @@
 	void *ioaddr = NULL;
 	static int board_idx = -1;
 	static int printed_version = 0;
+	u8 autoneg, duplex;
+	u16 speed;
 	int i, rc;
-	int option = -1, Cap10_100 = 0, Cap1000 = 0;
 
 	assert(pdev != NULL);
 	assert(ent != NULL);
@@ -822,6 +1101,25 @@
 	assert(dev != NULL);
 	assert(tp != NULL);
 
+	if (RTL_R8(PHYstatus) & TBI_Enable) {
+		tp->set_speed = rtl8169_set_speed_tbi;
+		tp->get_settings = rtl8169_gset_tbi;
+		tp->phy_reset_enable = rtl8169_tbi_reset_enable;
+		tp->phy_reset_pending = rtl8169_tbi_reset_pending;
+		tp->link_ok = rtl8169_tbi_link_ok;
+
+		tp->phy_1000_ctrl_reg = PHY_Cap_1000_Full; /* Implied by TBI */
+	} else {
+		tp->set_speed = rtl8169_set_speed_xmii;
+		tp->get_settings = rtl8169_gset_xmii;
+		tp->phy_reset_enable = rtl8169_xmii_reset_enable;
+		tp->phy_reset_pending = rtl8169_xmii_reset_pending;
+		tp->link_ok = rtl8169_xmii_link_ok;
+
+		tp->andy_s_phy_renegotiation_hack =
+			rtl8169_xmii_renegotiation_hack;
+	}
+
 	// Get MAC address.  FIXME: read EEPROM
 	for (i = 0; i < MAC_ADDR_LEN; i++)
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
@@ -836,9 +1134,12 @@
 	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
-//      dev->do_ioctl           = mii_ioctl;
-
-	tp = dev->priv;		// private data //
+#ifdef CONFIG_R8169_NAPI
+	dev->poll = rtl8169_poll;
+	dev->weight = R8169_NAPI_WEIGHT;
+	printk(KERN_INFO PFX "NAPI enabled\n");
+#endif
+	tp->intr_mask = 0xffff;
 	tp->pci_dev = pdev;
 	tp->mmio_addr = ioaddr;
 
@@ -885,95 +1186,12 @@
 		mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
 	}
 
-	// if TBI is not endbled
-	if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
-		int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
-
-		option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
-		// Force RTL8169 in 10/100/1000 Full/Half mode.
-		if (option > 0) {
-			printk(KERN_INFO "%s: Force-mode Enabled.\n",
-			       dev->name);
-			Cap10_100 = 0, Cap1000 = 0;
-			switch (option) {
-			case _10_Half:
-				Cap10_100 = PHY_Cap_10_Half_Or_Less;
-				Cap1000 = PHY_Cap_Null;
-				break;
-			case _10_Full:
-				Cap10_100 = PHY_Cap_10_Full_Or_Less;
-				Cap1000 = PHY_Cap_Null;
-				break;
-			case _100_Half:
-				Cap10_100 = PHY_Cap_100_Half_Or_Less;
-				Cap1000 = PHY_Cap_Null;
-				break;
-			case _100_Full:
-				Cap10_100 = PHY_Cap_100_Full_Or_Less;
-				Cap1000 = PHY_Cap_Null;
-				break;
-			case _1000_Full:
-				Cap10_100 = PHY_Cap_100_Full_Or_Less;
-				Cap1000 = PHY_Cap_1000_Full;
-				break;
-			default:
-				break;
-			}
-			mdio_write(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F));	//leave PHY_AUTO_NEGO_REG bit4:0 unchanged
-			mdio_write(ioaddr, PHY_1000_CTRL_REG, Cap1000);
-		} else {
-			printk(KERN_INFO "%s: Auto-negotiation Enabled.\n",
-			       dev->name);
+	rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
 
-			// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
-			mdio_write(ioaddr, PHY_AUTO_NEGO_REG,
-				   PHY_Cap_100_Full_Or_Less | (val & 0x1f));
-
-			// enable 1000 Full Mode
-			mdio_write(ioaddr, PHY_1000_CTRL_REG,
-				   PHY_Cap_1000_Full);
+	rtl8169_set_speed(dev, autoneg, speed, duplex);
 
-		}
-
-		// Enable auto-negotiation and restart auto-nigotiation
-		mdio_write(ioaddr, PHY_CTRL_REG,
-			   PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
-		udelay(100);
-
-		// wait for auto-negotiation process
-		for (i = 10000; i > 0; i--) {
-			//check if auto-negotiation complete
-			if (mdio_read(ioaddr, PHY_STAT_REG) &
-			    PHY_Auto_Neco_Comp) {
-				udelay(100);
-				option = RTL_R8(PHYstatus);
-				if (option & _1000bpsF) {
-					printk(KERN_INFO
-					       "%s: 1000Mbps Full-duplex operation.\n",
-					       dev->name);
-				} else {
-					printk(KERN_INFO
-					       "%s: %sMbps %s-duplex operation.\n",
-					       dev->name,
-					       (option & _100bps) ? "100" :
-					       "10",
-					       (option & FullDup) ? "Full" :
-					       "Half");
-				}
-				break;
-			} else {
-				udelay(100);
-			}
-		}		// end for-loop to wait for auto-negotiation process
-
-	} else {
-		udelay(100);
-		printk(KERN_INFO
-		       "%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
-		       dev->name,
-		       (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
-
-	}
+	if (RTL_R8(PHYstatus) & TBI_Enable)
+		printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
 
 	return 0;
 }
@@ -982,7 +1200,7 @@
 rtl8169_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 
 	assert(dev != NULL);
 	assert(tp != NULL);
@@ -1001,7 +1219,7 @@
 static int rtl8169_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
@@ -1042,7 +1260,7 @@
 static int
 rtl8169_open(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct pci_dev *pdev = tp->pci_dev;
 	int retval;
 
@@ -1074,6 +1292,8 @@
 	rtl8169_hw_start(dev);
 
 	rtl8169_request_timer(dev);
+
+	rtl8169_check_link_status(dev, tp, tp->mmio_addr);
 out:
 	return retval;
 
@@ -1091,7 +1311,7 @@
 static void
 rtl8169_hw_start(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	u32 i;
 
@@ -1102,8 +1322,7 @@
 	for (i = 1000; i > 0; i--) {
 		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
 			break;
-		else
-			udelay(10);
+		udelay(10);
 	}
 
 	RTL_W8(Cfg9346, Cfg9346_Unlock);
@@ -1114,8 +1333,8 @@
 	RTL_W16(RxMaxSize, RxPacketMaxSize);
 
 	// Set Rx Config register
-	i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].
-				 RxConfigMask);
+	i = rtl8169_rx_config |
+		(RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
 	RTL_W32(RxConfig, i);
 
 	/* Set DMA burst size and Interframe Gap Time */
@@ -1126,7 +1345,8 @@
 	RTL_W16(CPlusCmd, tp->cp_cmd);
 
 	if (tp->mac_version == RTL_GIGA_MAC_VER_D) {
-		dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n");
+		dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. "
+			"Bit-3 and bit-14 MUST be 1\n");
 		tp->cp_cmd |= (1 << 14) | PCIMulRW;
 		RTL_W16(CPlusCmd, tp->cp_cmd);
 	}
@@ -1151,7 +1371,6 @@
 	RTL_W16(IntrMask, rtl8169_intr_mask);
 
 	netif_start_queue(dev);
-
 }
 
 static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
@@ -1248,7 +1467,7 @@
 
 static int rtl8169_init_ring(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 
 	tp->cur_rx = tp->dirty_rx = 0;
 	tp->cur_tx = tp->dirty_tx = 0;
@@ -1302,10 +1521,11 @@
 static void
 rtl8169_tx_timeout(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	u8 tmp8;
 
+	printk(KERN_INFO "%s: TX Timeout\n", dev->name);
 	/* disable Tx, if not already */
 	tmp8 = RTL_R8(ChipCmd);
 	if (tmp8 & CmdTxEnb)
@@ -1328,9 +1548,9 @@
 static int
 rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
-	int entry = tp->cur_tx % NUM_TX_DESC;
+	unsigned int entry = tp->cur_tx % NUM_TX_DESC;
 	u32 len = skb->len;
 
 	if (unlikely(skb->len < ETH_ZLEN)) {
@@ -1382,7 +1602,7 @@
 rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 		     void *ioaddr)
 {
-	unsigned long dirty_tx, tx_left;
+	unsigned int dirty_tx, tx_left;
 
 	assert(dev != NULL);
 	assert(tp != NULL);
@@ -1392,7 +1612,7 @@
 	tx_left = tp->cur_tx - dirty_tx;
 
 	while (tx_left > 0) {
-		int entry = dirty_tx % NUM_TX_DESC;
+		unsigned int entry = dirty_tx % NUM_TX_DESC;
 		struct sk_buff *skb = tp->Tx_skbuff[entry];
 		u32 status;
 
@@ -1442,11 +1662,11 @@
 	return ret;
 }
 
-static void
+static int
 rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 		     void *ioaddr)
 {
-	unsigned long cur_rx, rx_left;
+	unsigned int cur_rx, rx_left, count;
 	int delta;
 
 	assert(dev != NULL);
@@ -1455,9 +1675,10 @@
 
 	cur_rx = tp->cur_rx;
 	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
+	rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
 
 	while (rx_left > 0) {
-		int entry = cur_rx % NUM_RX_DESC;
+		unsigned int entry = cur_rx % NUM_RX_DESC;
 		u32 status;
 
 		rmb();
@@ -1494,7 +1715,7 @@
 
 			skb_put(skb, pkt_size);
 			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
+			rtl8169_rx_skb(skb);
 
 			dev->last_rx = jiffies;
 			tp->stats.rx_bytes += pkt_size;
@@ -1505,13 +1726,15 @@
 		rx_left--;
 	}
 
+	count = cur_rx - tp->cur_rx;
 	tp->cur_rx = cur_rx;
 
 	delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
-	if (delta > 0)
-		tp->dirty_rx += delta;
-	else if (delta < 0)
+	if (delta < 0) {
 		printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name);
+		delta = 0;
+	}
+	tp->dirty_rx += delta;
 
 	/*
 	 * FIXME: until there is periodic timer to try and refill the ring,
@@ -1522,6 +1745,8 @@
 	 */
 	if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx)
 		printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name);
+
+	return count;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
@@ -1529,7 +1754,7 @@
 rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	int boguscnt = max_interrupt_work;
 	void *ioaddr = tp->mmio_addr;
 	int status = 0;
@@ -1543,18 +1768,31 @@
 			break;
 
 		handled = 1;
-/*
-		if (status & RxUnderrun)
-			link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
-*/
+
+		status &= tp->intr_mask;
 		RTL_W16(IntrStatus,
 			(status & RxFIFOOver) ? (status | RxOverflow) : status);
 
 		if (!(status & rtl8169_intr_mask))
 			break;
 
+		if (status & LinkChg)
+			rtl8169_check_link_status(dev, tp, ioaddr);
+
+#ifdef CONFIG_R8169_NAPI
+		RTL_W16(IntrMask, rtl8169_intr_mask & ~rtl8169_napi_event);
+		tp->intr_mask = ~rtl8169_napi_event;
+
+		if (likely(netif_rx_schedule_prep(dev)))
+			__netif_rx_schedule(dev);
+		else {
+			printk(KERN_INFO "%s: interrupt %x taken in poll\n",
+			       dev->name, status);	
+		}
+		break;
+#else
 		// Rx interrupt 
-		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) {
+		if (status & (RxOK | RxOverflow | RxFIFOOver)) {
 			rtl8169_rx_interrupt(dev, tp, ioaddr);
 		}
 		// Tx interrupt
@@ -1563,6 +1801,7 @@
 			rtl8169_tx_interrupt(dev, tp, ioaddr);
 			spin_unlock(&tp->lock);
 		}
+#endif
 
 		boguscnt--;
 	} while (boguscnt > 0);
@@ -1576,10 +1815,40 @@
 	return IRQ_RETVAL(handled);
 }
 
+#ifdef CONFIG_R8169_NAPI
+static int rtl8169_poll(struct net_device *dev, int *budget)
+{
+	unsigned int work_done, work_to_do = min(*budget, dev->quota);
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+
+	work_done = rtl8169_rx_interrupt(dev, tp, ioaddr);
+	rtl8169_tx_interrupt(dev, tp, ioaddr);
+
+	*budget -= work_done;
+	dev->quota -= work_done;
+
+	if ((work_done < work_to_do) || !netif_running(dev)) {
+		netif_rx_complete(dev);
+		tp->intr_mask = 0xffff;
+		/*
+		 * 20040426: the barrier is not strictly required but the
+		 * behavior of the irq handler could be less predictable
+		 * without it. Btw, the lack of flush for the posted pci
+		 * write is safe - FR
+		 */
+		smp_wmb();
+		RTL_W16(IntrMask, rtl8169_intr_mask);
+	}
+
+	return (work_done >= work_to_do);
+}
+#endif
+
 static int
 rtl8169_close(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct pci_dev *pdev = tp->pci_dev;
 	void *ioaddr = tp->mmio_addr;
 
@@ -1621,7 +1890,7 @@
 static void
 rtl8169_set_rx_mode(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 	u32 mc_filter[2];	/* Multicast hash filter */
@@ -1655,10 +1924,8 @@
 
 	spin_lock_irqsave(&tp->lock, flags);
 
-	tmp =
-	    rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
-					   rtl_chip_info[tp->chipset].
-					   RxConfigMask);
+	tmp = rtl8169_rx_config | rx_mode |
+	      (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
 
 	RTL_W32(RxConfig, tmp);
 	RTL_W32(MAR0 + 0, mc_filter[0]);
@@ -1675,7 +1942,7 @@
  */
 static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
--- diff/drivers/net/s2io.h	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/s2io.h	2004-05-27 18:34:17.000000000 +0100
@@ -748,27 +748,6 @@
 #define SMALL_RXD_CNT	40 * (MAX_RXDS_PER_BLOCK+1)
 #define LARGE_RXD_CNT	100 * (MAX_RXDS_PER_BLOCK+1)
 
-/*  OS related system calls */
-#ifndef readq
-static inline u64 readq(void *addr)
-{
-	u64 ret = 0;
-	ret = readl(addr + 4);
-	ret <<= 32;
-	ret |= readl(addr);
-
-	return ret;
-}
-#endif
-
-#ifndef writeq
-static inline void writeq(u64 val, void *addr)
-{
-	writel((u32) (val), addr);
-	writel((u32) (val >> 32), (addr + 4));
-}
-#endif
-
 /*  Interrupt related values of Xena */
 
 #define ENABLE_INTRS    1
--- diff/drivers/net/sis900.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/sis900.c	2004-05-27 18:34:17.000000000 +0100
@@ -18,6 +18,7 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+               Jan.  7 2004 Grischa Jacobs - Skip mii's with MII_STAT_FAULT set
    Rev 1.08.07 Nov.  2 2003 Daniele Venzano <webvenza@libero.it> add suspend/resume support
    Rev 1.08.06 Sep. 24 2002 Mufasa Yang bug fix for Tx timeout & add SiS963 support
    Rev 1.08.05 Jun.  6 2002 Mufasa Yang bug fix for read_eeprom & Tx descriptor over-boundary
@@ -116,6 +117,7 @@
 #define	HOME 	0x0001
 #define LAN	0x0002
 #define MIX	0x0003
+#define UNKNOWN	0x0
 } mii_chip_table[] = {
 	{ "SiS 900 Internal MII PHY", 		0x001d, 0x8000, LAN },
 	{ "SiS 7014 Physical Layer Solution", 	0x0016, 0xf830, LAN },
@@ -260,9 +262,13 @@
 	u8 reg;
 	int i;
 
-	if ((isa_bridge = pci_find_device(0x1039, 0x0008, isa_bridge)) == NULL) {
-		printk("%s: Can not find ISA bridge\n", net_dev->name);
-		return 0;
+	isa_bridge = pci_find_device(PCI_VENDOR_ID_SI, 0x0008, isa_bridge);
+	if (!isa_bridge) {
+		isa_bridge = pci_find_device(PCI_VENDOR_ID_SI, 0x0018, isa_bridge);
+		if (!isa_bridge) {
+			printk("%s: Can not find ISA bridge\n", net_dev->name);
+			return 0;
+		}
 	}
 	pci_read_config_byte(isa_bridge, 0x48, &reg);
 	pci_write_config_byte(isa_bridge, 0x48, reg | 0x40);
@@ -541,6 +547,10 @@
 			/* the mii is not accessible, try next one */
 			continue;
 		
+		if (mii_status & MII_STAT_FAULT)
+			/* ignore mii with the fault bit set */
+			continue;
+
 		if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {
 			printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n");
 			mii_phy = sis_priv->first_mii;
@@ -573,9 +583,11 @@
 				break;
 			}
 			
-		if( !mii_chip_table[i].phy_id1 )
+		if( !mii_chip_table[i].phy_id1 ) {
 			printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",
-			       net_dev->name, phy_addr);			
+			       net_dev->name, phy_addr);
+			mii_phy->phy_types = UNKNOWN;
+		}
 	}
 	
 	if (sis_priv->mii == NULL) {
@@ -640,15 +652,15 @@
 static u16 sis900_default_phy(struct net_device * net_dev)
 {
 	struct sis900_private * sis_priv = net_dev->priv;
- 	struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL;
+ 	struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL, *phy_lan = NULL;
 	u16 status;
 
         for( phy=sis_priv->first_mii; phy; phy=phy->next ){
 		status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
 		status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
 
-		/* Link ON & Not select deafalut PHY */
-		 if ( (status & MII_STAT_LINK) && !(default_phy) )
+		/* Link ON & Not select default PHY & not ghost PHY */
+		 if ( (status & MII_STAT_LINK) && !default_phy && (phy->phy_types != UNKNOWN) )
 		 	default_phy = phy;
 		 else{
 			status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL);
@@ -656,12 +668,16 @@
 				status | MII_CNTL_AUTO | MII_CNTL_ISOLATE);
 			if( phy->phy_types == HOME )
 				phy_home = phy;
+			else if (phy->phy_types == LAN)
+				phy_lan = phy;
 		 }
 	}
 
-	if( (!default_phy) && phy_home )
+	if( !default_phy && phy_home )
 		default_phy = phy_home;
-	else if(!default_phy)
+	else if( !default_phy && phy_lan )
+		default_phy = phy_lan;
+	else if ( !default_phy )
 		default_phy = sis_priv->first_mii;
 
 	if( sis_priv->mii != default_phy ){
@@ -2195,6 +2211,7 @@
 		return 0;
 
 	netif_stop_queue(net_dev);
+	netif_device_detach(net_dev);
 
 	/* Stop the chip's Tx and Rx Status Machine */
 	outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr);
--- diff/drivers/net/sis900.h	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/sis900.h	2004-05-27 18:34:17.000000000 +0100
@@ -77,7 +77,7 @@
 	IE = 0x00000001
 };
 
-/* maximum dma burst fro transmission and receive*/
+/* maximum dma burst for transmission and receive */
 #define MAX_DMA_RANGE	7	/* actually 0 means MAXIMUM !! */
 #define TxMXDMA_shift   	20
 #define RxMXDMA_shift    20
@@ -86,7 +86,7 @@
 	DMA_BURST_512 = 0,	DMA_BURST_64 = 5
 };
 
-/* transmit FIFO threshholds */
+/* transmit FIFO thresholds */
 #define TX_FILL_THRESH   16	/* 1/4 FIFO size */
 #define TxFILLT_shift   	8
 #define TxDRNT_shift    	0
@@ -140,7 +140,7 @@
 	EEREQ = 0x00000400, EEDONE = 0x00000200, EEGNT = 0x00000100
 };
 
-/* Manamgement Data I/O (mdio) frame */
+/* Management Data I/O (mdio) frame */
 #define MIIread         0x6000
 #define MIIwrite        0x5002
 #define MIIpmdShift     7
--- diff/drivers/net/sk98lin/skvpd.c	2004-05-19 22:11:58.000000000 +0100
+++ source/drivers/net/sk98lin/skvpd.c	2004-05-27 18:34:17.000000000 +0100
@@ -468,6 +468,17 @@
 	
 	pAC->vpd.vpd_size = vpd_size;
 
+	/* Asus K8V Se Deluxe bugfix. Correct VPD content */
+	/* MBo April 2004 */
+	if (((unsigned char)pAC->vpd.vpd_buf[0x3f] == 0x38) &&
+	    ((unsigned char)pAC->vpd.vpd_buf[0x40] == 0x3c) &&
+	    ((unsigned char)pAC->vpd.vpd_buf[0x41] == 0x45)) {
+		printk("sk98lin: Asus mainboard with buggy VPD? "
+				"Correcting data.\n");
+		pAC->vpd.vpd_buf[0x40] = 0x38;
+	}
+
+
 	/* find the end tag of the RO area */
 	if (!(r = vpd_find_para(pAC, VPD_RV, &rp))) {
 		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
--- diff/drivers/net/sun3lance.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/sun3lance.c	2004-05-27 18:34:17.000000000 +0100
@@ -42,7 +42,6 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/dvma.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
--- diff/drivers/net/tg3.c	2004-05-27 13:41:19.000000000 +0100
+++ source/drivers/net/tg3.c	2004-05-27 18:34:17.000000000 +0100
@@ -56,8 +56,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.4"
-#define DRV_MODULE_RELDATE	"May 14, 2004"
+#define DRV_MODULE_VERSION	"3.5"
+#define DRV_MODULE_RELDATE	"May 25, 2004"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -128,7 +128,8 @@
 /* minimum number of free TX descriptors required to wake up TX process */
 #define TG3_TX_WAKEUP_THRESH		(TG3_TX_RING_SIZE / 4)
 
-#define TG3_NUM_STATS		25	/* number of ETHTOOL_GSTATS u64's */
+/* number of ETHTOOL_GSTATS u64's */
+#define TG3_NUM_STATS		(sizeof(struct tg3_ethtool_stats)/sizeof(u64))
 
 static char version[] __devinitdata =
 	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -216,10 +217,13 @@
 struct {
 	char string[ETH_GSTRING_LEN];
 } ethtool_stats_keys[TG3_NUM_STATS] = {
+	{ "rx_octets" },
 	{ "rx_fragments" },
 	{ "rx_ucast_packets" },
+	{ "rx_mcast_packets" },
 	{ "rx_bcast_packets" },
 	{ "rx_fcs_errors" },
+	{ "rx_align_errors" },
 	{ "rx_xon_pause_rcvd" },
 	{ "rx_xoff_pause_rcvd" },
 	{ "rx_mac_ctrl_rcvd" },
@@ -229,6 +233,19 @@
 	{ "rx_undersize_packets" },
 	{ "rx_in_length_errors" },
 	{ "rx_out_length_errors" },
+	{ "rx_64_or_less_octet_packets" },
+	{ "rx_65_to_127_octet_packets" },
+	{ "rx_128_to_255_octet_packets" },
+	{ "rx_256_to_511_octet_packets" },
+	{ "rx_512_to_1023_octet_packets" },
+	{ "rx_1024_to_1522_octet_packets" },
+	{ "rx_1523_to_2047_octet_packets" },
+	{ "rx_2048_to_4095_octet_packets" },
+	{ "rx_4096_to_8191_octet_packets" },
+	{ "rx_8192_to_9022_octet_packets" },
+
+	{ "tx_octets" },
+	{ "tx_collisions" },
 
 	{ "tx_xon_sent" },
 	{ "tx_xoff_sent" },
@@ -239,9 +256,43 @@
 	{ "tx_deferred" },
 	{ "tx_excessive_collisions" },
 	{ "tx_late_collisions" },
+	{ "tx_collide_2times" },
+	{ "tx_collide_3times" },
+	{ "tx_collide_4times" },
+	{ "tx_collide_5times" },
+	{ "tx_collide_6times" },
+	{ "tx_collide_7times" },
+	{ "tx_collide_8times" },
+	{ "tx_collide_9times" },
+	{ "tx_collide_10times" },
+	{ "tx_collide_11times" },
+	{ "tx_collide_12times" },
+	{ "tx_collide_13times" },
+	{ "tx_collide_14times" },
+	{ "tx_collide_15times" },
 	{ "tx_ucast_packets" },
 	{ "tx_mcast_packets" },
-	{ "tx_bcast_packets" }
+	{ "tx_bcast_packets" },
+	{ "tx_carrier_sense_errors" },
+	{ "tx_discards" },
+	{ "tx_errors" },
+
+	{ "dma_writeq_full" },
+	{ "dma_write_prioq_full" },
+	{ "rxbds_empty" },
+	{ "rx_discards" },
+	{ "rx_errors" },
+	{ "rx_threshold_hit" },
+
+	{ "dma_readq_full" },
+	{ "dma_read_prioq_full" },
+	{ "tx_comp_queue_full" },
+
+	{ "ring_set_send_prod_index" },
+	{ "ring_status_update" },
+	{ "nic_irqs" },
+	{ "nic_avoided_irqs" },
+	{ "nic_tx_threshold_hit" }
 };
 
 static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
@@ -1053,6 +1104,8 @@
 static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
 {
 	u32 new_tg3_flags = 0;
+	u32 old_rx_mode = tp->rx_mode;
+	u32 old_tx_mode = tp->tx_mode;
 
 	if (local_adv & ADVERTISE_PAUSE_CAP) {
 		if (local_adv & ADVERTISE_PAUSE_ASYM) {
@@ -1083,10 +1136,18 @@
 	else
 		tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
 
+	if (old_rx_mode != tp->rx_mode) {
+		tw32_f(MAC_RX_MODE, tp->rx_mode);
+	}
+	
 	if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
 		tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
 	else
 		tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
+
+	if (old_tx_mode != tp->tx_mode) {
+		tw32_f(MAC_TX_MODE, tp->tx_mode);
+	}
 }
 
 static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex)
@@ -2472,7 +2533,7 @@
 
 static int tg3_poll(struct net_device *netdev, int *budget)
 {
-	struct tg3 *tp = netdev->priv;
+	struct tg3 *tp = netdev_priv(netdev);
 	struct tg3_hw_status *sblk = tp->hw_status;
 	unsigned long flags;
 	int done;
@@ -2554,7 +2615,7 @@
 static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	struct tg3_hw_status *sblk = tp->hw_status;
 	unsigned long flags;
 	unsigned int handled = 1;
@@ -2634,7 +2695,7 @@
 
 static void tg3_tx_timeout(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 
 	printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
 	       dev->name);
@@ -2750,7 +2811,7 @@
 
 static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	dma_addr_t mapping;
 	unsigned int i;
 	u32 len, entry, base_flags, mss;
@@ -2954,7 +3015,7 @@
 
 static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	dma_addr_t mapping;
 	u32 len, entry, base_flags, mss;
 	unsigned long flags;
@@ -3124,7 +3185,7 @@
 
 static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 
 	if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
 		return -EINVAL;
@@ -4741,7 +4802,7 @@
 
 static int tg3_set_mac_addr(struct net_device *dev, void *p)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	struct sockaddr *addr = p;
 
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -5533,7 +5594,7 @@
 
 static int tg3_open(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	int err;
 
 	spin_lock_irq(&tp->lock);
@@ -5836,7 +5897,7 @@
 
 static int tg3_close(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -5921,10 +5982,13 @@
 	if (!hw_stats)
 		return old_estats;
 
+	ESTAT_ADD(rx_octets);
 	ESTAT_ADD(rx_fragments);
 	ESTAT_ADD(rx_ucast_packets);
+	ESTAT_ADD(rx_mcast_packets);
 	ESTAT_ADD(rx_bcast_packets);
 	ESTAT_ADD(rx_fcs_errors);
+	ESTAT_ADD(rx_align_errors);
 	ESTAT_ADD(rx_xon_pause_rcvd);
 	ESTAT_ADD(rx_xoff_pause_rcvd);
 	ESTAT_ADD(rx_mac_ctrl_rcvd);
@@ -5934,7 +5998,19 @@
 	ESTAT_ADD(rx_undersize_packets);
 	ESTAT_ADD(rx_in_length_errors);
 	ESTAT_ADD(rx_out_length_errors);
+	ESTAT_ADD(rx_64_or_less_octet_packets);
+	ESTAT_ADD(rx_65_to_127_octet_packets);
+	ESTAT_ADD(rx_128_to_255_octet_packets);
+	ESTAT_ADD(rx_256_to_511_octet_packets);
+	ESTAT_ADD(rx_512_to_1023_octet_packets);
+	ESTAT_ADD(rx_1024_to_1522_octet_packets);
+	ESTAT_ADD(rx_1523_to_2047_octet_packets);
+	ESTAT_ADD(rx_2048_to_4095_octet_packets);
+	ESTAT_ADD(rx_4096_to_8191_octet_packets);
+	ESTAT_ADD(rx_8192_to_9022_octet_packets);
 
+	ESTAT_ADD(tx_octets);
+	ESTAT_ADD(tx_collisions);
 	ESTAT_ADD(tx_xon_sent);
 	ESTAT_ADD(tx_xoff_sent);
 	ESTAT_ADD(tx_flow_control);
@@ -5944,16 +6020,50 @@
 	ESTAT_ADD(tx_deferred);
 	ESTAT_ADD(tx_excessive_collisions);
 	ESTAT_ADD(tx_late_collisions);
+	ESTAT_ADD(tx_collide_2times);
+	ESTAT_ADD(tx_collide_3times);
+	ESTAT_ADD(tx_collide_4times);
+	ESTAT_ADD(tx_collide_5times);
+	ESTAT_ADD(tx_collide_6times);
+	ESTAT_ADD(tx_collide_7times);
+	ESTAT_ADD(tx_collide_8times);
+	ESTAT_ADD(tx_collide_9times);
+	ESTAT_ADD(tx_collide_10times);
+	ESTAT_ADD(tx_collide_11times);
+	ESTAT_ADD(tx_collide_12times);
+	ESTAT_ADD(tx_collide_13times);
+	ESTAT_ADD(tx_collide_14times);
+	ESTAT_ADD(tx_collide_15times);
 	ESTAT_ADD(tx_ucast_packets);
 	ESTAT_ADD(tx_mcast_packets);
 	ESTAT_ADD(tx_bcast_packets);
+	ESTAT_ADD(tx_carrier_sense_errors);
+	ESTAT_ADD(tx_discards);
+	ESTAT_ADD(tx_errors);
+
+	ESTAT_ADD(dma_writeq_full);
+	ESTAT_ADD(dma_write_prioq_full);
+	ESTAT_ADD(rxbds_empty);
+	ESTAT_ADD(rx_discards);
+	ESTAT_ADD(rx_errors);
+	ESTAT_ADD(rx_threshold_hit);
+
+	ESTAT_ADD(dma_readq_full);
+	ESTAT_ADD(dma_read_prioq_full);
+	ESTAT_ADD(tx_comp_queue_full);
+
+	ESTAT_ADD(ring_set_send_prod_index);
+	ESTAT_ADD(ring_status_update);
+	ESTAT_ADD(nic_irqs);
+	ESTAT_ADD(nic_avoided_irqs);
+	ESTAT_ADD(nic_tx_threshold_hit);
 
 	return estats;
 }
 
 static struct net_device_stats *tg3_get_stats(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	struct net_device_stats *stats = &tp->net_stats;
 	struct net_device_stats *old_stats = &tp->net_stats_prev;
 	struct tg3_hw_stats *hw_stats = tp->hw_stats;
@@ -5977,7 +6087,8 @@
 		get_stat64(&hw_stats->tx_octets);
 
 	stats->rx_errors = old_stats->rx_errors +
-		get_stat64(&hw_stats->rx_errors);
+		get_stat64(&hw_stats->rx_errors) +
+		get_stat64(&hw_stats->rx_discards);
 	stats->tx_errors = old_stats->tx_errors +
 		get_stat64(&hw_stats->tx_errors) +
 		get_stat64(&hw_stats->tx_mac_errors) +
@@ -6044,7 +6155,7 @@
 
 static void __tg3_set_rx_mode(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	u32 rx_mode;
 
 	rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
@@ -6108,7 +6219,7 @@
 
 static void tg3_set_rx_mode(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 
 	spin_lock_irq(&tp->lock);
 	__tg3_set_rx_mode(dev);
@@ -6126,7 +6237,7 @@
 		struct ethtool_regs *regs, void *_p)
 {
 	u32 *p = _p;
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	u8 *orig_p = _p;
 	int i;
 
@@ -6257,7 +6368,7 @@
 
 static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-  	struct tg3 *tp = dev->priv;
+  	struct tg3 *tp = netdev_priv(dev);
   
 	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
 					tp->link_config.phy_is_low_power)
@@ -6292,7 +6403,7 @@
   
 static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
 	    tp->link_config.phy_is_low_power)
@@ -6331,7 +6442,7 @@
   
 static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	strcpy(info->driver, DRV_MODULE_NAME);
 	strcpy(info->version, DRV_MODULE_VERSION);
@@ -6340,7 +6451,7 @@
   
 static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	wol->supported = WAKE_MAGIC;
 	wol->wolopts = 0;
@@ -6351,7 +6462,7 @@
   
 static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	if (wol->wolopts & ~WAKE_MAGIC)
 		return -EINVAL;
@@ -6372,20 +6483,20 @@
   
 static u32 tg3_get_msglevel(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	return tp->msg_enable;
 }
   
 static void tg3_set_msglevel(struct net_device *dev, u32 value)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	tp->msg_enable = value;
 }
   
 #if TG3_TSO_SUPPORT != 0
 static int tg3_set_tso(struct net_device *dev, u32 value)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 
 	if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
 		if (value)
@@ -6398,7 +6509,7 @@
   
 static int tg3_nway_reset(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	u32 bmcr;
 	int r;
   
@@ -6417,7 +6528,7 @@
   
 static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	ering->rx_max_pending = TG3_RX_RING_SIZE - 1;
 	ering->rx_mini_max_pending = 0;
@@ -6431,7 +6542,7 @@
   
 static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
 	    (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
@@ -6462,7 +6573,7 @@
   
 static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
 	epause->rx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0;
@@ -6471,7 +6582,7 @@
   
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	tg3_netif_stop(tp);
 	spin_lock_irq(&tp->lock);
@@ -6499,13 +6610,13 @@
   
 static u32 tg3_get_rx_csum(struct net_device *dev)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
 }
   
 static int tg3_set_rx_csum(struct net_device *dev, u32 data)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
 		if (data != 0)
@@ -6525,7 +6636,7 @@
   
 static int tg3_set_tx_csum(struct net_device *dev, u32 data)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
   
 	if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
 		if (data != 0)
@@ -6562,13 +6673,13 @@
 				   struct ethtool_stats *estats, u64 *tmp_stats)
 {
 	struct tg3 *tp = dev->priv;
-	memcpy(tmp_stats, &tp->estats, sizeof(tp->estats));
+	memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
 }
 
 static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	int err;
 
 	switch(cmd) {
@@ -6608,7 +6719,7 @@
 #if TG3_VLAN_TAG_USED
 static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
@@ -6624,7 +6735,7 @@
 
 static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
@@ -8047,7 +8158,7 @@
 	dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid;
 #endif
 
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 	tp->pdev = pdev;
 	tp->dev = dev;
 	tp->pm_cap = pm_cap;
@@ -8268,8 +8379,10 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 
 	if (dev) {
+		struct tg3 *tp = netdev_priv(dev);
+
 		unregister_netdev(dev);
-		iounmap((void *) ((struct tg3 *)(dev->priv))->regs);
+		iounmap((void *)tp->regs);
 		free_netdev(dev);
 		pci_release_regions(pdev);
 		pci_disable_device(pdev);
@@ -8280,7 +8393,7 @@
 static int tg3_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	int err;
 
 	if (!netif_running(dev))
@@ -8327,7 +8440,7 @@
 static int tg3_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = netdev_priv(dev);
 	int err;
 
 	if (!netif_running(dev))
--- diff/drivers/net/tg3.h	2004-05-27 13:41:19.000000000 +0100
+++ source/drivers/net/tg3.h	2004-05-27 18:34:17.000000000 +0100
@@ -1845,10 +1845,13 @@
 
 struct tg3_ethtool_stats {
 	/* Statistics maintained by Receive MAC. */
+	u64 	    	rx_octets;
 	u64		rx_fragments;
 	u64		rx_ucast_packets;
+	u64		rx_mcast_packets;
 	u64		rx_bcast_packets;
 	u64		rx_fcs_errors;
+	u64		rx_align_errors;
 	u64		rx_xon_pause_rcvd;
 	u64		rx_xoff_pause_rcvd;
 	u64		rx_mac_ctrl_rcvd;
@@ -1858,8 +1861,20 @@
 	u64		rx_undersize_packets;
 	u64		rx_in_length_errors;
 	u64		rx_out_length_errors;
+	u64		rx_64_or_less_octet_packets;
+	u64		rx_65_to_127_octet_packets;
+	u64		rx_128_to_255_octet_packets;
+	u64		rx_256_to_511_octet_packets;
+	u64		rx_512_to_1023_octet_packets;
+	u64		rx_1024_to_1522_octet_packets;
+	u64		rx_1523_to_2047_octet_packets;
+	u64		rx_2048_to_4095_octet_packets;
+	u64		rx_4096_to_8191_octet_packets;
+	u64		rx_8192_to_9022_octet_packets;
 
 	/* Statistics maintained by Transmit MAC. */
+	u64		tx_octets;
+	u64		tx_collisions;
 	u64		tx_xon_sent;
 	u64		tx_xoff_sent;
 	u64		tx_flow_control;
@@ -1869,9 +1884,46 @@
 	u64		tx_deferred;
 	u64		tx_excessive_collisions;
 	u64		tx_late_collisions;
+	u64		tx_collide_2times;
+	u64		tx_collide_3times;
+	u64		tx_collide_4times;
+	u64		tx_collide_5times;
+	u64		tx_collide_6times;
+	u64		tx_collide_7times;
+	u64		tx_collide_8times;
+	u64		tx_collide_9times;
+	u64		tx_collide_10times;
+	u64		tx_collide_11times;
+	u64		tx_collide_12times;
+	u64		tx_collide_13times;
+	u64		tx_collide_14times;
+	u64		tx_collide_15times;
 	u64		tx_ucast_packets;
 	u64		tx_mcast_packets;
 	u64		tx_bcast_packets;
+	u64		tx_carrier_sense_errors;
+	u64		tx_discards;
+	u64		tx_errors;
+
+	/* Statistics maintained by Receive List Placement. */
+	u64		dma_writeq_full;
+	u64		dma_write_prioq_full;
+	u64		rxbds_empty;
+	u64		rx_discards;
+	u64		rx_errors;
+	u64		rx_threshold_hit;
+
+	/* Statistics maintained by Send Data Initiator. */
+	u64		dma_readq_full;
+	u64		dma_read_prioq_full;
+	u64		tx_comp_queue_full;
+
+	/* Statistics maintained by Host Coalescing. */
+	u64		ring_set_send_prod_index;
+	u64		ring_status_update;
+	u64		nic_irqs;
+	u64		nic_avoided_irqs;
+	u64		nic_tx_threshold_hit;
 };
 
 struct tg3 {
--- diff/drivers/net/tokenring/olympic.c	2004-05-19 22:11:59.000000000 +0100
+++ source/drivers/net/tokenring/olympic.c	2004-05-27 18:34:17.000000000 +0100
@@ -1806,7 +1806,7 @@
 
 static void __exit olympic_pci_cleanup(void)
 {
-	return pci_unregister_driver(&olympic_driver) ; 
+	pci_unregister_driver(&olympic_driver) ; 
 }	
 
 
--- diff/drivers/net/tulip/interrupt.c	2004-05-19 22:11:59.000000000 +0100
+++ source/drivers/net/tulip/interrupt.c	2004-05-27 18:34:17.000000000 +0100
@@ -133,6 +133,10 @@
 			   tp->rx_ring[entry].status);
 
        do {
+		if (inl(dev->base_addr + CSR5) == 0xffffffff) {
+			printk(KERN_DEBUG " In tulip_poll(), hardware disappeared.\n");
+			break;
+		}
                /* Acknowledge current RX interrupt sources. */
                outl((RxIntr | RxNoBuf), dev->base_addr + CSR5);
  
--- diff/drivers/net/tulip/tulip_core.c	2004-05-19 22:11:59.000000000 +0100
+++ source/drivers/net/tulip/tulip_core.c	2004-05-27 18:34:17.000000000 +0100
@@ -1513,7 +1513,7 @@
 		}
 	}
 	/* Lite-On boards have the address byte-swapped. */
-	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0)
+	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0 || dev->dev_addr[0] == 0x02)
 		&&  dev->dev_addr[1] == 0x00)
 		for (i = 0; i < 6; i+=2) {
 			char tmp = dev->dev_addr[i];
--- diff/drivers/net/tulip/winbond-840.c	2004-05-19 22:12:00.000000000 +0100
+++ source/drivers/net/tulip/winbond-840.c	2004-05-27 18:34:17.000000000 +0100
@@ -1292,14 +1292,8 @@
 				pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry],
 							    np->rx_skbuff[entry]->len,
 							    PCI_DMA_FROMDEVICE);
-				/* Call copy + cksum if available. */
-#if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-					   pkt_len);
-#endif
 				pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry],
 							       np->rx_skbuff[entry]->len,
 							       PCI_DMA_FROMDEVICE);
--- diff/drivers/net/via-rhine.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/via-rhine.c	2004-05-27 18:34:17.000000000 +0100
@@ -74,8 +74,8 @@
 
 	LK1.1.11:
 	- David Woodhouse: Set dev->base_addr before the first time we call
-					   wait_for_reset(). It's a lot happier that way.
-					   Free np->tx_bufs only if we actually allocated it.
+			   wait_for_reset(). It's a lot happier that way.
+			   Free np->tx_bufs only if we actually allocated it.
 
 	LK1.1.12:
 	- Martin Eriksson: Allow Memory-Mapped IO to be enabled.
@@ -85,7 +85,7 @@
 	- Replace some MII-related magic numbers with constants
 
 	LK1.1.14 (Ivan G.):
- 	- fixes comments for Rhine-III
+	- fixes comments for Rhine-III
 	- removes W_MAX_TIMEOUT (unused)
 	- adds HasDavicomPhy for Rhine-I (basis: linuxfet driver; my card
 	  is R-I and has Davicom chip, flag is referenced in kernel driver)
@@ -96,10 +96,10 @@
 	- transmit frame queue message is off by one - fixed
 	- adds IntrNormalSummary to "Something Wicked" exclusion list
 	  so normal interrupts will not trigger the message (src: Donald Becker)
- 	(Roger Luethi)
- 	- show confused chip where to continue after Tx error
- 	- location of collision counter is chip specific
- 	- allow selecting backoff algorithm (module parameter)
+	(Roger Luethi)
+	- show confused chip where to continue after Tx error
+	- location of collision counter is chip specific
+	- allow selecting backoff algorithm (module parameter)
 
 	LK1.1.15 (jgarzik):
 	- Use new MII lib helper generic_mii_ioctl
@@ -128,14 +128,14 @@
 */
 
 #define DRV_NAME	"via-rhine"
-#define DRV_VERSION	"1.1.19-2.5"
-#define DRV_RELDATE	"July-12-2003"
+#define DRV_VERSION	"1.1.20-2.6"
+#define DRV_RELDATE	"May-23-2004"
 
 
 /* A few user-configurable values.
    These may be modified when a driver module is loaded. */
 
-static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+static int debug = 1;	/* 1 normal messages, 0 quiet .. 7 verbose. */
 static int max_interrupt_work = 20;
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -155,12 +155,12 @@
    Use option values 0x10 and 0x100 for forcing half duplex fixed speed.
    Use option values 0x20 and 0x200 for forcing full duplex operation.
 */
-#define MAX_UNITS 8		/* More are supported, limit only on options */
+#define MAX_UNITS	8	/* More are supported, limit only on options */
 static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
-   The Rhine has a 64 element 8390-like hash table.  */
+   The Rhine has a 64 element 8390-like hash table. */
 static const int multicast_filter_limit = 32;
 
 
@@ -172,16 +172,16 @@
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
 #define TX_RING_SIZE	16
-#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
+#define TX_QUEUE_LEN	10	/* Limit ring entries actually used. */
 #define RX_RING_SIZE	16
 
 
 /* Operational parameters that usually are not changed. */
 
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (2*HZ)
+#define TX_TIMEOUT	(2*HZ)
 
-#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+#define PKT_BUF_SZ	1536	/* Size of each temporary Rx buffer.*/
 
 #if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
 #warning  You must compile this file with the correct options!
@@ -206,7 +206,7 @@
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/crc32.h>
-#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -214,18 +214,16 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION "  " DRV_RELDATE "  Written by Donald Becker\n"
-KERN_INFO "  http://www.scyld.com/network/via-rhine.html\n";
+KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n";
 
 static char shortname[] = DRV_NAME;
 
 
-/* This driver was written to use PCI memory space, however most versions
-   of the Rhine only work correctly with I/O space accesses. */
+/* This driver was written to use PCI memory space. Some early versions
+   of the Rhine may only work correctly with I/O space accesses. */
 #ifdef CONFIG_VIA_RHINE_MMIO
-#define USE_MEM
+#define USE_MMIO
 #else
-#define USE_IO
 #undef readb
 #undef readw
 #undef readl
@@ -258,7 +256,7 @@
 MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)");
 
 /*
-				Theory of Operation
+		Theory of Operation
 
 I. Board Compatibility
 
@@ -281,7 +279,7 @@
 
 This driver uses two statically allocated fixed-size descriptor lists
 formed into rings by a branch from the final descriptor to the beginning of
-the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
+the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
 
 IIIb/c. Transmit/Receive Structure
 
@@ -292,29 +290,29 @@
 
 The driver allocates full frame size skbuffs for the Rx ring buffers at
 open() time and passes the skb->data field to the chip as receive data
-buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
+buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
 a fresh skbuff is allocated and the frame is copied to the new skbuff.
 When the incoming frame is larger, the skbuff is passed directly up the
-protocol stack.  Buffers consumed this way are replaced by newly allocated
-skbuffs in the last phase of via_rhine_rx().
+protocol stack. Buffers consumed this way are replaced by newly allocated
+skbuffs in the last phase of rhine_rx().
 
 The RX_COPYBREAK value is chosen to trade-off the memory wasted by
 using a full-sized skbuff for small frames vs. the copying costs of larger
-frames.  New boards are typically used in generously configured machines
+frames. New boards are typically used in generously configured machines
 and the underfilled buffers have negligible impact compared to the benefit of
 a single allocation size, so the default value of zero results in never
-copying packets.  When copying is done, the cost is usually mitigated by using
-a combined copy/checksum routine.  Copying also preloads the cache, which is
+copying packets. When copying is done, the cost is usually mitigated by using
+a combined copy/checksum routine. Copying also preloads the cache, which is
 most useful with small frames.
 
 Since the VIA chips are only able to transfer data to buffers on 32 bit
 boundaries, the IP header at offset 14 in an ethernet frame isn't
-longword aligned for further processing.  Copying these unaligned buffers
+longword aligned for further processing. Copying these unaligned buffers
 has the beneficial effect of 16-byte aligning the IP header.
 
 IIId. Synchronization
 
-The driver runs as two independent, single-threaded flows of control.  One
+The driver runs as two independent, single-threaded flows of control. One
 is the send-packet routine, which enforces single-threaded use by the
 dev->priv->lock spinlock. The other thread is the interrupt handler, which
 is single threaded by the hardware and interrupt handling software.
@@ -324,7 +322,7 @@
 is not available it stops the transmit queue by calling netif_stop_queue.
 
 The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
+from the Tx ring. After reaping the stats, it marks the Tx queue entry as
 empty by incrementing the dirty_tx mark. If at least half of the entries in
 the Rx ring are available the transmit queue is woken up if it was stopped.
 
@@ -350,7 +348,7 @@
 */
 
 
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
+/* This table drives the PCI probe routines. It's mostly boilerplate in all
    of the drivers, and will likely be provided by some future kernel.
    Note the matching code -- the first table entry matchs all 56** cards but
    second only the 1234 card.
@@ -361,14 +359,14 @@
 	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
 
-enum via_rhine_chips {
+enum rhine_chips {
 	VT86C100A = 0,
 	VT6102,
 	VT6105,
 	VT6105M
 };
 
-struct via_rhine_chip_info {
+struct rhine_chip_info {
 	const char *name;
 	u16 pci_flags;
 	int io_size;
@@ -378,9 +376,10 @@
 
 enum chip_capability_flags {
 	CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4,
-	ReqTxAlign=0x10, HasWOL=0x20, };
+	ReqTxAlign=0x10, HasWOL=0x20,
+};
 
-#ifdef USE_MEM
+#ifdef USE_MMIO
 #define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1)
 #else
 #define RHINE_IOTYPE (PCI_USES_IO  | PCI_USES_MASTER | PCI_ADDR0)
@@ -388,8 +387,8 @@
 /* Beware of PCI posted writes */
 #define IOSYNC	do { readb(dev->base_addr + StationAddr); } while (0)
 
-/* directly indexed by enum via_rhine_chips, above */
-static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata =
+/* directly indexed by enum rhine_chips, above */
+static struct rhine_chip_info rhine_chip_info[] __devinitdata =
 {
 	{ "VIA VT86C100A Rhine", RHINE_IOTYPE, 128,
 	  CanHaveMII | ReqTxAlign | HasDavicomPhy },
@@ -401,15 +400,15 @@
 	  CanHaveMII | HasWOL },
 };
 
-static struct pci_device_id via_rhine_pci_tbl[] =
+static struct pci_device_id rhine_pci_tbl[] =
 {
 	{0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A},
 	{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102},
 	{0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, /* 6105{,L,LOM} */
 	{0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M},
-	{0,}			/* terminate list */
+	{0,}	/* terminate list */
 };
-MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl);
+MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
 
 
 /* Offsets to the device registers. */
@@ -432,7 +431,7 @@
 	BackCaptureEffect=0x04, BackRandom=0x08
 };
 
-#ifdef USE_MEM
+#ifdef USE_MMIO
 /* Registers we check that mmio and reg are the same. */
 int mmio_verify_registers[] = {
 	RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD,
@@ -469,7 +468,7 @@
 };
 
 /* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */
-#define TXDESC 0x00e08000
+#define TXDESC		0x00e08000
 
 enum rx_status_bits {
 	RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
@@ -489,7 +488,7 @@
 };
 
 #define MAX_MII_CNT	4
-struct netdev_private {
+struct rhine_private {
 	/* Descriptor rings */
 	struct rx_desc *rx_ring;
 	struct tx_desc *tx_ring;
@@ -517,48 +516,48 @@
 	/* Frequently used values: keep some adjacent for cache effect. */
 	int chip_id, drv_flags;
 	struct rx_desc *rx_head_desc;
-	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
+	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
-	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
-	u16 chip_cmd;						/* Current setting for ChipCmd */
+	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
+	u16 chip_cmd;			/* Current setting for ChipCmd */
 
 	/* These values are keep track of the transceiver/media in use. */
-	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int default_port:4;	/* Last dev->if_port value. */
 	u8 tx_thresh, rx_thresh;
 
 	/* MII transceiver section. */
-	unsigned char phys[MAX_MII_CNT];			/* MII device addresses. */
-	unsigned int mii_cnt;			/* number of MIIs found, but only the first one is used */
-	u16 mii_status;						/* last read MII status */
+	unsigned char phys[MAX_MII_CNT];	/* MII device addresses. */
+	unsigned int mii_cnt;		/* number of MIIs found, but only the first one is used */
+	u16 mii_status;			/* last read MII status */
 	struct mii_if_info mii_if;
 };
 
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-static int  via_rhine_open(struct net_device *dev);
-static void via_rhine_check_duplex(struct net_device *dev);
-static void via_rhine_timer(unsigned long data);
-static void via_rhine_tx_timeout(struct net_device *dev);
-static int  via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static void via_rhine_tx(struct net_device *dev);
-static void via_rhine_rx(struct net_device *dev);
-static void via_rhine_error(struct net_device *dev, int intr_status);
-static void via_rhine_set_rx_mode(struct net_device *dev);
-static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
+static int  rhine_open(struct net_device *dev);
+static void rhine_check_duplex(struct net_device *dev);
+static void rhine_timer(unsigned long data);
+static void rhine_tx_timeout(struct net_device *dev);
+static int  rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static void rhine_tx(struct net_device *dev);
+static void rhine_rx(struct net_device *dev);
+static void rhine_error(struct net_device *dev, int intr_status);
+static void rhine_set_rx_mode(struct net_device *dev);
+static struct net_device_stats *rhine_get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static struct ethtool_ops netdev_ethtool_ops;
-static int  via_rhine_close(struct net_device *dev);
+static int  rhine_close(struct net_device *dev);
 
 static inline u32 get_intr_status(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	u32 intr_status;
 
 	intr_status = readw(ioaddr + IntrStatus);
 	/* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
-	if (np->chip_id == VT6102)
+	if (rp->chip_id == VT6102)
 		intr_status |= readb(ioaddr + IntrStatus2) << 16;
 	return intr_status;
 }
@@ -590,7 +589,7 @@
 			boguscnt ? "succeeded" : "failed");
 }
 
-#ifdef USE_MEM
+#ifdef USE_MMIO
 static void __devinit enable_mmio(long ioaddr, int chip_id)
 {
 	int n;
@@ -616,19 +615,19 @@
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static void via_rhine_poll(struct net_device *dev)
+static void rhine_poll(struct net_device *dev)
 {
 	disable_irq(dev->irq);
-	via_rhine_interrupt(dev->irq, (void *)dev, NULL);
+	rhine_interrupt(dev->irq, (void *)dev, NULL);
 	enable_irq(dev->irq);
 }
 #endif
 
-static int __devinit via_rhine_init_one (struct pci_dev *pdev,
-					 const struct pci_device_id *ent)
+static int __devinit rhine_init_one(struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
 {
 	struct net_device *dev;
-	struct netdev_private *np;
+	struct rhine_private *rp;
 	int i, option;
 	int chip_id = (int) ent->driver_data;
 	static int card_idx = -1;
@@ -636,7 +635,7 @@
 	long memaddr;
 	int io_size;
 	int pci_flags;
-#ifdef USE_MEM
+#ifdef USE_MMIO
 	long ioaddr0;
 #endif
 
@@ -649,34 +648,36 @@
 
 	card_idx++;
 	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-	io_size = via_rhine_chip_info[chip_id].io_size;
-	pci_flags = via_rhine_chip_info[chip_id].pci_flags;
+	io_size = rhine_chip_info[chip_id].io_size;
+	pci_flags = rhine_chip_info[chip_id].pci_flags;
 
-	if (pci_enable_device (pdev))
+	if (pci_enable_device(pdev))
 		goto err_out;
 
 	/* this should always be supported */
 	if (pci_set_dma_mask(pdev, 0xffffffff)) {
-		printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n");
+		printk(KERN_ERR "32-bit PCI DMA addresses not supported by "
+		       "the card!?\n");
 		goto err_out;
 	}
 
 	/* sanity check */
-	if ((pci_resource_len (pdev, 0) < io_size) ||
-	    (pci_resource_len (pdev, 1) < io_size)) {
-		printk (KERN_ERR "Insufficient PCI resources, aborting\n");
+	if ((pci_resource_len(pdev, 0) < io_size) ||
+	    (pci_resource_len(pdev, 1) < io_size)) {
+		printk(KERN_ERR "Insufficient PCI resources, aborting\n");
 		goto err_out;
 	}
 
-	ioaddr = pci_resource_start (pdev, 0);
-	memaddr = pci_resource_start (pdev, 1);
+	ioaddr = pci_resource_start(pdev, 0);
+	memaddr = pci_resource_start(pdev, 1);
 
 	if (pci_flags & PCI_USES_MASTER)
-		pci_set_master (pdev);
+		pci_set_master(pdev);
 
-	dev = alloc_etherdev(sizeof(*np));
+	dev = alloc_etherdev(sizeof(*rp));
 	if (dev == NULL) {
-		printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx);
+		printk(KERN_ERR "init_ethernet failed for card #%d\n",
+		       card_idx);
 		goto err_out;
 	}
 	SET_MODULE_OWNER(dev);
@@ -685,14 +686,14 @@
 	if (pci_request_regions(pdev, shortname))
 		goto err_out_free_netdev;
 
-#ifdef USE_MEM
+#ifdef USE_MMIO
 	ioaddr0 = ioaddr;
 	enable_mmio(ioaddr0, chip_id);
 
-	ioaddr = (long) ioremap (memaddr, io_size);
+	ioaddr = (long) ioremap(memaddr, io_size);
 	if (!ioaddr) {
-		printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%lX\n",
-				pci_name(pdev), io_size, memaddr);
+		printk(KERN_ERR "ioremap failed for device %s, region 0x%X "
+		       "@ 0x%lX\n", pci_name(pdev), io_size, memaddr);
 		goto err_out_free_res;
 	}
 
@@ -703,15 +704,15 @@
 		unsigned char a = inb(ioaddr0+reg);
 		unsigned char b = readb(ioaddr+reg);
 		if (a != b) {
-			printk (KERN_ERR "MMIO do not match PIO [%02x] (%02x != %02x)\n",
-					reg, a, b);
+			printk(KERN_ERR "MMIO do not match PIO [%02x] "
+			       "(%02x != %02x)\n", reg, a, b);
 			goto err_out_unmap;
 		}
 	}
-#endif
+#endif /* USE_MMIO */
 
 	/* D-Link provided reset code (with comment additions) */
-	if (via_rhine_chip_info[chip_id].drv_flags & HasWOL) {
+	if (rhine_chip_info[chip_id].drv_flags & HasWOL) {
 		unsigned char byOrgValue;
 
 		/* clear sticky bit before reset & read ethernet address */
@@ -735,14 +736,14 @@
 	wait_for_reset(dev, chip_id, shortname);
 
 	/* Reload the station address from the EEPROM. */
-#ifdef USE_IO
-	reload_eeprom(ioaddr);
-#else
+#ifdef USE_MMIO
 	reload_eeprom(ioaddr0);
 	/* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO.
 	   If reload_eeprom() was done first this could be avoided, but it is
 	   not known if that still works with the "win98-reboot" problem. */
 	enable_mmio(ioaddr0, chip_id);
+#else
+	reload_eeprom(ioaddr);
 #endif
 
 	for (i = 0; i < 6; i++)
@@ -756,7 +757,7 @@
 	if (chip_id == VT6102) {
 		/*
 		 * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA
-		 * turned on.  it makes MAC receive magic packet
+		 * turned on. it makes MAC receive magic packet
 		 * automatically. So, we turn it off. (D-Link)
 		 */
 		writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA);
@@ -765,38 +766,38 @@
 	/* Select backoff algorithm */
 	if (backoff)
 		writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff),
-			ioaddr + ConfigD);
+		       ioaddr + ConfigD);
 
 	dev->irq = pdev->irq;
 
-	np = dev->priv;
-	spin_lock_init (&np->lock);
-	np->chip_id = chip_id;
-	np->drv_flags = via_rhine_chip_info[chip_id].drv_flags;
-	np->pdev = pdev;
-	np->mii_if.dev = dev;
-	np->mii_if.mdio_read = mdio_read;
-	np->mii_if.mdio_write = mdio_write;
-	np->mii_if.phy_id_mask = 0x1f;
-	np->mii_if.reg_num_mask = 0x1f;
+	rp = netdev_priv(dev);
+	spin_lock_init(&rp->lock);
+	rp->chip_id = chip_id;
+	rp->drv_flags = rhine_chip_info[chip_id].drv_flags;
+	rp->pdev = pdev;
+	rp->mii_if.dev = dev;
+	rp->mii_if.mdio_read = mdio_read;
+	rp->mii_if.mdio_write = mdio_write;
+	rp->mii_if.phy_id_mask = 0x1f;
+	rp->mii_if.reg_num_mask = 0x1f;
 
 	if (dev->mem_start)
 		option = dev->mem_start;
 
 	/* The chip-specific entries in the device structure. */
-	dev->open = via_rhine_open;
-	dev->hard_start_xmit = via_rhine_start_tx;
-	dev->stop = via_rhine_close;
-	dev->get_stats = via_rhine_get_stats;
-	dev->set_multicast_list = via_rhine_set_rx_mode;
+	dev->open = rhine_open;
+	dev->hard_start_xmit = rhine_start_tx;
+	dev->stop = rhine_close;
+	dev->get_stats = rhine_get_stats;
+	dev->set_multicast_list = rhine_set_rx_mode;
 	dev->do_ioctl = netdev_ioctl;
 	dev->ethtool_ops = &netdev_ethtool_ops;
-	dev->tx_timeout = via_rhine_tx_timeout;
+	dev->tx_timeout = rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 #ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = via_rhine_poll;
+	dev->poll_controller = rhine_poll;
 #endif
-	if (np->drv_flags & ReqTxAlign)
+	if (rp->drv_flags & ReqTxAlign)
 		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 
 	/* dev->name not defined before register_netdev()! */
@@ -807,40 +808,41 @@
 	/* The lower four bits are the media type. */
 	if (option > 0) {
 		if (option & 0x220)
-			np->mii_if.full_duplex = 1;
-		np->default_port = option & 15;
+			rp->mii_if.full_duplex = 1;
+		rp->default_port = option & 15;
 	}
-	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		np->mii_if.full_duplex = 1;
+	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
+		rp->mii_if.full_duplex = 1;
 
-	if (np->mii_if.full_duplex) {
-		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-			   " disabled.\n", dev->name);
-		np->mii_if.force_media = 1;
+	if (rp->mii_if.full_duplex) {
+		printk(KERN_INFO "%s: Set to forced full duplex, "
+		       "autonegotiation disabled.\n", dev->name);
+		rp->mii_if.force_media = 1;
 	}
 
 	printk(KERN_INFO "%s: %s at 0x%lx, ",
-		   dev->name, via_rhine_chip_info[chip_id].name,
-		   (pci_flags & PCI_USES_IO) ? ioaddr : memaddr);
+	       dev->name, rhine_chip_info[chip_id].name,
+	       (pci_flags & PCI_USES_IO) ? ioaddr : memaddr);
 
 	for (i = 0; i < 5; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
+		printk("%2.2x:", dev->dev_addr[i]);
 	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq);
 
 	pci_set_drvdata(pdev, dev);
 
-	if (np->drv_flags & CanHaveMII) {
+	if (rp->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
-		np->phys[0] = 1;		/* Standard for this chip. */
+		rp->phys[0] = 1;		/* Standard for this chip. */
 		for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) {
 			int mii_status = mdio_read(dev, phy, 1);
-			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
-				np->phys[phy_idx++] = phy;
-				np->mii_if.advertising = mdio_read(dev, phy, 4);
-				printk(KERN_INFO "%s: MII PHY found at address %d, status "
-					   "0x%4.4x advertising %4.4x Link %4.4x.\n",
-					   dev->name, phy, mii_status, np->mii_if.advertising,
-					   mdio_read(dev, phy, 5));
+			if (mii_status != 0xffff && mii_status != 0x0000) {
+				rp->phys[phy_idx++] = phy;
+				rp->mii_if.advertising = mdio_read(dev, phy, 4);
+				printk(KERN_INFO "%s: MII PHY found at address "
+				       "%d, status 0x%4.4x advertising %4.4x "
+				       "Link %4.4x.\n", dev->name, phy,
+				       mii_status, rp->mii_if.advertising,
+				       mdio_read(dev, phy, 5));
 
 				/* set IFF_RUNNING */
 				if (mii_status & BMSR_LSTATUS)
@@ -851,49 +853,50 @@
 				break;
 			}
 		}
-		np->mii_cnt = phy_idx;
-		np->mii_if.phy_id = np->phys[0];
+		rp->mii_cnt = phy_idx;
+		rp->mii_if.phy_id = rp->phys[0];
 	}
 
 	/* Allow forcing the media type. */
 	if (option > 0) {
 		if (option & 0x220)
-			np->mii_if.full_duplex = 1;
-		np->default_port = option & 0x3ff;
-		if (np->default_port & 0x330) {
+			rp->mii_if.full_duplex = 1;
+		rp->default_port = option & 0x3ff;
+		if (option & 0x330) {
 			/* FIXME: shouldn't someone check this variable? */
-			/* np->medialock = 1; */
-			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
-				   (option & 0x300 ? 100 : 10),
-				   (option & 0x220 ? "full" : "half"));
-			if (np->mii_cnt)
-				mdio_write(dev, np->phys[0], MII_BMCR,
-						   ((option & 0x300) ? 0x2000 : 0) |  /* 100mbps? */
-						   ((option & 0x220) ? 0x0100 : 0));  /* Full duplex? */
+			/* rp->medialock = 1; */
+			printk(KERN_INFO " Forcing %dMbs %s-duplex "
+				"operation.\n",
+			       (option & 0x300 ? 100 : 10),
+			       (option & 0x220 ? "full" : "half"));
+			if (rp->mii_cnt)
+				mdio_write(dev, rp->phys[0], MII_BMCR,
+					   ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */
+					   ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */
 		}
 	}
 
 	return 0;
 
 err_out_unmap:
-#ifdef USE_MEM
+#ifdef USE_MMIO
 	iounmap((void *)ioaddr);
 err_out_free_res:
 #endif
 	pci_release_regions(pdev);
 err_out_free_netdev:
-	free_netdev (dev);
+	free_netdev(dev);
 err_out:
 	return -ENODEV;
 }
 
 static int alloc_ring(struct net_device* dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	void *ring;
 	dma_addr_t ring_dma;
 
-	ring = pci_alloc_consistent(np->pdev,
+	ring = pci_alloc_consistent(rp->pdev,
 				    RX_RING_SIZE * sizeof(struct rx_desc) +
 				    TX_RING_SIZE * sizeof(struct tx_desc),
 				    &ring_dma);
@@ -901,11 +904,12 @@
 		printk(KERN_ERR "Could not allocate DMA memory.\n");
 		return -ENOMEM;
 	}
-	if (np->drv_flags & ReqTxAlign) {
-		np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
-								   &np->tx_bufs_dma);
-		if (np->tx_bufs == NULL) {
-			pci_free_consistent(np->pdev,
+	if (rp->drv_flags & ReqTxAlign) {
+		rp->tx_bufs = pci_alloc_consistent(rp->pdev,
+						   PKT_BUF_SZ * TX_RING_SIZE,
+						   &rp->tx_bufs_dma);
+		if (rp->tx_bufs == NULL) {
+			pci_free_consistent(rp->pdev,
 				    RX_RING_SIZE * sizeof(struct rx_desc) +
 				    TX_RING_SIZE * sizeof(struct tx_desc),
 				    ring, ring_dma);
@@ -913,137 +917,138 @@
 		}
 	}
 
-	np->rx_ring = ring;
-	np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc);
-	np->rx_ring_dma = ring_dma;
-	np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc);
+	rp->rx_ring = ring;
+	rp->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc);
+	rp->rx_ring_dma = ring_dma;
+	rp->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc);
 
 	return 0;
 }
 
 void free_ring(struct net_device* dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 
-	pci_free_consistent(np->pdev,
+	pci_free_consistent(rp->pdev,
 			    RX_RING_SIZE * sizeof(struct rx_desc) +
 			    TX_RING_SIZE * sizeof(struct tx_desc),
-			    np->rx_ring, np->rx_ring_dma);
-	np->tx_ring = NULL;
+			    rp->rx_ring, rp->rx_ring_dma);
+	rp->tx_ring = NULL;
 
-	if (np->tx_bufs)
-		pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
-							np->tx_bufs, np->tx_bufs_dma);
+	if (rp->tx_bufs)
+		pci_free_consistent(rp->pdev, PKT_BUF_SZ * TX_RING_SIZE,
+				    rp->tx_bufs, rp->tx_bufs_dma);
 
-	np->tx_bufs = NULL;
+	rp->tx_bufs = NULL;
 
 }
 
 static void alloc_rbufs(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	dma_addr_t next;
 	int i;
 
-	np->dirty_rx = np->cur_rx = 0;
+	rp->dirty_rx = rp->cur_rx = 0;
 
-	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-	np->rx_head_desc = &np->rx_ring[0];
-	next = np->rx_ring_dma;
+	rp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+	rp->rx_head_desc = &rp->rx_ring[0];
+	next = rp->rx_ring_dma;
 
 	/* Init the ring entries */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].rx_status = 0;
-		np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
+		rp->rx_ring[i].rx_status = 0;
+		rp->rx_ring[i].desc_length = cpu_to_le32(rp->rx_buf_sz);
 		next += sizeof(struct rx_desc);
-		np->rx_ring[i].next_desc = cpu_to_le32(next);
-		np->rx_skbuff[i] = 0;
+		rp->rx_ring[i].next_desc = cpu_to_le32(next);
+		rp->rx_skbuff[i] = 0;
 	}
 	/* Mark the last entry as wrapping the ring. */
-	np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma);
+	rp->rx_ring[i-1].next_desc = cpu_to_le32(rp->rx_ring_dma);
 
 	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-		np->rx_skbuff[i] = skb;
+		struct sk_buff *skb = dev_alloc_skb(rp->rx_buf_sz);
+		rp->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;
 		skb->dev = dev;                 /* Mark as being used by this device. */
 
-		np->rx_skbuff_dma[i] =
-			pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
-						   PCI_DMA_FROMDEVICE);
+		rp->rx_skbuff_dma[i] =
+			pci_map_single(rp->pdev, skb->tail, rp->rx_buf_sz,
+				       PCI_DMA_FROMDEVICE);
 
-		np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]);
-		np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
+		rp->rx_ring[i].addr = cpu_to_le32(rp->rx_skbuff_dma[i]);
+		rp->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
 	}
-	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+	rp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 }
 
 static void free_rbufs(struct net_device* dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	int i;
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].rx_status = 0;
-		np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
-		if (np->rx_skbuff[i]) {
-			pci_unmap_single(np->pdev,
-							 np->rx_skbuff_dma[i],
-							 np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(np->rx_skbuff[i]);
+		rp->rx_ring[i].rx_status = 0;
+		rp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		if (rp->rx_skbuff[i]) {
+			pci_unmap_single(rp->pdev,
+					 rp->rx_skbuff_dma[i],
+					 rp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(rp->rx_skbuff[i]);
 		}
-		np->rx_skbuff[i] = 0;
+		rp->rx_skbuff[i] = 0;
 	}
 }
 
 static void alloc_tbufs(struct net_device* dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	dma_addr_t next;
 	int i;
 
-	np->dirty_tx = np->cur_tx = 0;
-	next = np->tx_ring_dma;
+	rp->dirty_tx = rp->cur_tx = 0;
+	next = rp->tx_ring_dma;
 	for (i = 0; i < TX_RING_SIZE; i++) {
-		np->tx_skbuff[i] = 0;
-		np->tx_ring[i].tx_status = 0;
-		np->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
+		rp->tx_skbuff[i] = 0;
+		rp->tx_ring[i].tx_status = 0;
+		rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
 		next += sizeof(struct tx_desc);
-		np->tx_ring[i].next_desc = cpu_to_le32(next);
-		np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ];
+		rp->tx_ring[i].next_desc = cpu_to_le32(next);
+		rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ];
 	}
-	np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma);
+	rp->tx_ring[i-1].next_desc = cpu_to_le32(rp->tx_ring_dma);
 
 }
 
 static void free_tbufs(struct net_device* dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	int i;
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
-		np->tx_ring[i].tx_status = 0;
-		np->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
-		np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
-		if (np->tx_skbuff[i]) {
-			if (np->tx_skbuff_dma[i]) {
-				pci_unmap_single(np->pdev,
-								 np->tx_skbuff_dma[i],
-								 np->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
+		rp->tx_ring[i].tx_status = 0;
+		rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
+		rp->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		if (rp->tx_skbuff[i]) {
+			if (rp->tx_skbuff_dma[i]) {
+				pci_unmap_single(rp->pdev,
+						 rp->tx_skbuff_dma[i],
+						 rp->tx_skbuff[i]->len,
+						 PCI_DMA_TODEVICE);
 			}
-			dev_kfree_skb(np->tx_skbuff[i]);
+			dev_kfree_skb(rp->tx_skbuff[i]);
 		}
-		np->tx_skbuff[i] = 0;
-		np->tx_buf[i] = 0;
+		rp->tx_skbuff[i] = 0;
+		rp->tx_buf[i] = 0;
 	}
 }
 
 static void init_registers(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -1054,38 +1059,39 @@
 	writew(0x0006, ioaddr + PCIBusConfig);	/* Tune configuration??? */
 	/* Configure initial FIFO thresholds. */
 	writeb(0x20, ioaddr + TxConfig);
-	np->tx_thresh = 0x20;
-	np->rx_thresh = 0x60;			/* Written in via_rhine_set_rx_mode(). */
-	np->mii_if.full_duplex = 0;
+	rp->tx_thresh = 0x20;
+	rp->rx_thresh = 0x60;		/* Written in rhine_set_rx_mode(). */
+	rp->mii_if.full_duplex = 0;
 
 	if (dev->if_port == 0)
-		dev->if_port = np->default_port;
+		dev->if_port = rp->default_port;
 
-	writel(np->rx_ring_dma, ioaddr + RxRingPtr);
-	writel(np->tx_ring_dma, ioaddr + TxRingPtr);
+	writel(rp->rx_ring_dma, ioaddr + RxRingPtr);
+	writel(rp->tx_ring_dma, ioaddr + TxRingPtr);
 
-	via_rhine_set_rx_mode(dev);
+	rhine_set_rx_mode(dev);
 
 	/* Enable interrupts by setting the interrupt mask. */
 	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
-		   IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
-		   IntrTxDone | IntrTxError | IntrTxUnderrun |
-		   IntrPCIErr | IntrStatsMax | IntrLinkChange,
-		   ioaddr + IntrEnable);
-
-	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
-	if (np->mii_if.force_media)
-		np->chip_cmd |= CmdFDuplex;
-	writew(np->chip_cmd, ioaddr + ChipCmd);
+	       IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
+	       IntrTxDone | IntrTxError | IntrTxUnderrun |
+	       IntrPCIErr | IntrStatsMax | IntrLinkChange,
+	       ioaddr + IntrEnable);
+
+	rp->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
+	if (rp->mii_if.force_media)
+		rp->chip_cmd |= CmdFDuplex;
+	writew(rp->chip_cmd, ioaddr + ChipCmd);
 
-	via_rhine_check_duplex(dev);
+	rhine_check_duplex(dev);
 
-	/* The LED outputs of various MII xcvrs should be configured.  */
+	/* The LED outputs of various MII xcvrs should be configured. */
 	/* For NS or Mison phys, turn on bit 1 in register 0x17 */
 	/* For ESI phys, turn on bit 7 in register 0x17. */
-	mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
-			   (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
+	mdio_write(dev, rp->phys[0], 0x17, mdio_read(dev, rp->phys[0], 0x17) |
+		   (rp->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
 }
+
 /* Read and write over the MII Management Data I/O (MDIO) interface. */
 
 static int mdio_read(struct net_device *dev, int phy_id, int regnum)
@@ -1099,7 +1105,7 @@
 	writeb(0x00, ioaddr + MIICmd);
 	writeb(phy_id, ioaddr + MIIPhyAddr);
 	writeb(regnum, ioaddr + MIIRegAddr);
-	writeb(0x40, ioaddr + MIICmd);			/* Trigger read */
+	writeb(0x40, ioaddr + MIICmd);		/* Trigger read */
 	boguscnt = 1024;
 	while ((readb(ioaddr + MIICmd) & 0x40) && --boguscnt > 0)
 		;
@@ -1108,20 +1114,20 @@
 
 static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int boguscnt = 1024;
 
-	if (phy_id == np->phys[0]) {
+	if (phy_id == rp->phys[0]) {
 		switch (regnum) {
-		case MII_BMCR:					/* Is user forcing speed/duplex? */
-			if (value & 0x9000)			/* Autonegotiation. */
-				np->mii_if.force_media = 0;
+		case MII_BMCR:		/* Is user forcing speed/duplex? */
+			if (value & 0x9000)	/* Autonegotiation. */
+				rp->mii_if.force_media = 0;
 			else
-				np->mii_if.full_duplex = (value & 0x0100) ? 1 : 0;
+				rp->mii_if.full_duplex = (value & 0x0100) ? 1 : 0;
 			break;
 		case MII_ADVERTISE:
-			np->mii_if.advertising = value;
+			rp->mii_if.advertising = value;
 			break;
 		}
 	}
@@ -1133,128 +1139,130 @@
 	writeb(phy_id, ioaddr + MIIPhyAddr);
 	writeb(regnum, ioaddr + MIIRegAddr);
 	writew(value, ioaddr + MIIData);
-	writeb(0x20, ioaddr + MIICmd);			/* Trigger write. */
+	writeb(0x20, ioaddr + MIICmd);		/* Trigger write. */
 }
 
 
-static int via_rhine_open(struct net_device *dev)
+static int rhine_open(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 
 	/* Reset the chip. */
 	writew(CmdReset, ioaddr + ChipCmd);
 
-	i = request_irq(np->pdev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev);
+	i = request_irq(rp->pdev->irq, &rhine_interrupt, SA_SHIRQ, dev->name,
+			dev);
 	if (i)
 		return i;
 
 	if (debug > 1)
-		printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
-			   dev->name, np->pdev->irq);
+		printk(KERN_DEBUG "%s: rhine_open() irq %d.\n",
+		       dev->name, rp->pdev->irq);
 
 	i = alloc_ring(dev);
 	if (i)
 		return i;
 	alloc_rbufs(dev);
 	alloc_tbufs(dev);
-	wait_for_reset(dev, np->chip_id, dev->name);
+	wait_for_reset(dev, rp->chip_id, dev->name);
 	init_registers(dev);
 	if (debug > 2)
-		printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x "
-			   "MII status: %4.4x.\n",
-			   dev->name, readw(ioaddr + ChipCmd),
-			   mdio_read(dev, np->phys[0], MII_BMSR));
+		printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x "
+		       "MII status: %4.4x.\n",
+		       dev->name, readw(ioaddr + ChipCmd),
+		       mdio_read(dev, rp->phys[0], MII_BMSR));
 
 	netif_start_queue(dev);
 
 	/* Set the timer to check for link beat. */
-	init_timer(&np->timer);
-	np->timer.expires = jiffies + 2 * HZ/100;
-	np->timer.data = (unsigned long)dev;
-	np->timer.function = &via_rhine_timer;				/* timer handler */
-	add_timer(&np->timer);
+	init_timer(&rp->timer);
+	rp->timer.expires = jiffies + 2 * HZ/100;
+	rp->timer.data = (unsigned long)dev;
+	rp->timer.function = &rhine_timer;		/* timer handler */
+	add_timer(&rp->timer);
 
 	return 0;
 }
 
-static void via_rhine_check_duplex(struct net_device *dev)
+static void rhine_check_duplex(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
-	int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
-	int negotiated = mii_lpa & np->mii_if.advertising;
+	int mii_lpa = mdio_read(dev, rp->phys[0], MII_LPA);
+	int negotiated = mii_lpa & rp->mii_if.advertising;
 	int duplex;
 
-	if (np->mii_if.force_media  ||  mii_lpa == 0xffff)
+	if (rp->mii_if.force_media || mii_lpa == 0xffff)
 		return;
 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-	if (np->mii_if.full_duplex != duplex) {
-		np->mii_if.full_duplex = duplex;
+	if (rp->mii_if.full_duplex != duplex) {
+		rp->mii_if.full_duplex = duplex;
 		if (debug)
-			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-				   " partner capability of %4.4x.\n", dev->name,
-				   duplex ? "full" : "half", np->phys[0], mii_lpa);
+			printk(KERN_INFO "%s: Setting %s-duplex based on "
+			       "MII #%d link partner capability of %4.4x.\n",
+			       dev->name, duplex ? "full" : "half",
+			       rp->phys[0], mii_lpa);
 		if (duplex)
-			np->chip_cmd |= CmdFDuplex;
+			rp->chip_cmd |= CmdFDuplex;
 		else
-			np->chip_cmd &= ~CmdFDuplex;
-		writew(np->chip_cmd, ioaddr + ChipCmd);
+			rp->chip_cmd &= ~CmdFDuplex;
+		writew(rp->chip_cmd, ioaddr + ChipCmd);
 	}
 }
 
 
-static void via_rhine_timer(unsigned long data)
+static void rhine_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
 	int mii_status;
 
 	if (debug > 3) {
 		printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
-			   dev->name, readw(ioaddr + IntrStatus));
+		       dev->name, readw(ioaddr + IntrStatus));
 	}
 
-	spin_lock_irq (&np->lock);
+	spin_lock_irq (&rp->lock);
 
-	via_rhine_check_duplex(dev);
+	rhine_check_duplex(dev);
 
 	/* make IFF_RUNNING follow the MII status bit "Link established" */
-	mii_status = mdio_read(dev, np->phys[0], MII_BMSR);
-	if ( (mii_status & BMSR_LSTATUS) != (np->mii_status & BMSR_LSTATUS) ) {
+	mii_status = mdio_read(dev, rp->phys[0], MII_BMSR);
+	if ((mii_status & BMSR_LSTATUS) != (rp->mii_status & BMSR_LSTATUS)) {
 		if (mii_status & BMSR_LSTATUS)
 			netif_carrier_on(dev);
 		else
 			netif_carrier_off(dev);
 	}
-	np->mii_status = mii_status;
+	rp->mii_status = mii_status;
 
-	spin_unlock_irq (&np->lock);
+	spin_unlock_irq(&rp->lock);
 
-	np->timer.expires = jiffies + next_tick;
-	add_timer(&np->timer);
+	rp->timer.expires = jiffies + next_tick;
+	add_timer(&rp->timer);
 }
 
 
-static void via_rhine_tx_timeout (struct net_device *dev)
+static void rhine_tx_timeout(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
-	printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
-		"%4.4x, resetting...\n",
-		dev->name, readw (ioaddr + IntrStatus),
-		mdio_read (dev, np->phys[0], MII_BMSR));
+	printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
+	       "%4.4x, resetting...\n",
+	       dev->name, readw(ioaddr + IntrStatus),
+	       mdio_read(dev, rp->phys[0], MII_BMSR));
 
 	dev->if_port = 0;
 
 	/* protect against concurrent rx interrupts */
-	disable_irq(np->pdev->irq);
+	disable_irq(rp->pdev->irq);
 
-	spin_lock(&np->lock);
+	spin_lock(&rp->lock);
 
 	/* Reset the chip. */
 	writew(CmdReset, ioaddr + ChipCmd);
@@ -1266,20 +1274,20 @@
 	alloc_rbufs(dev);
 
 	/* Reinitialize the hardware. */
-	wait_for_reset(dev, np->chip_id, dev->name);
+	wait_for_reset(dev, rp->chip_id, dev->name);
 	init_registers(dev);
 
-	spin_unlock(&np->lock);
-	enable_irq(np->pdev->irq);
+	spin_unlock(&rp->lock);
+	enable_irq(rp->pdev->irq);
 
 	dev->trans_start = jiffies;
-	np->stats.tx_errors++;
+	rp->stats.tx_errors++;
 	netif_wake_queue(dev);
 }
 
-static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
+static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	unsigned entry;
 	u32 intr_status;
 
@@ -1287,7 +1295,7 @@
 	   with the "ownership" bits last. */
 
 	/* Calculate the next Tx descriptor entry. */
-	entry = np->cur_tx % TX_RING_SIZE;
+	entry = rp->cur_tx % TX_RING_SIZE;
 
 	if (skb->len < ETH_ZLEN) {
 		skb = skb_padto(skb, ETH_ZLEN);
@@ -1295,39 +1303,40 @@
 			return 0;
 	}
 
-	np->tx_skbuff[entry] = skb;
+	rp->tx_skbuff[entry] = skb;
 
-	if ((np->drv_flags & ReqTxAlign) &&
-		(((long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_HW)
-		) {
+	if ((rp->drv_flags & ReqTxAlign) &&
+	    (((long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_HW)) {
 		/* Must use alignment buffer. */
 		if (skb->len > PKT_BUF_SZ) {
 			/* packet too long, drop it */
 			dev_kfree_skb(skb);
-			np->tx_skbuff[entry] = NULL;
-			np->stats.tx_dropped++;
+			rp->tx_skbuff[entry] = NULL;
+			rp->stats.tx_dropped++;
 			return 0;
 		}
-		skb_copy_and_csum_dev(skb, np->tx_buf[entry]);
-		np->tx_skbuff_dma[entry] = 0;
-		np->tx_ring[entry].addr = cpu_to_le32(np->tx_bufs_dma +
-										  (np->tx_buf[entry] - np->tx_bufs));
+		skb_copy_and_csum_dev(skb, rp->tx_buf[entry]);
+		rp->tx_skbuff_dma[entry] = 0;
+		rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_bufs_dma +
+						      (rp->tx_buf[entry] -
+						       rp->tx_bufs));
 	} else {
-		np->tx_skbuff_dma[entry] =
-			pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
-		np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]);
+		rp->tx_skbuff_dma[entry] =
+			pci_map_single(rp->pdev, skb->data, skb->len,
+				       PCI_DMA_TODEVICE);
+		rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_skbuff_dma[entry]);
 	}
 
-	np->tx_ring[entry].desc_length =
+	rp->tx_ring[entry].desc_length =
 		cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
 	/* lock eth irq */
-	spin_lock_irq (&np->lock);
+	spin_lock_irq(&rp->lock);
 	wmb();
-	np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
+	rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
 	wmb();
 
-	np->cur_tx++;
+	rp->cur_tx++;
 
 	/* Non-x86 Todo: explicitly flush cache lines here. */
 
@@ -1337,27 +1346,27 @@
 	 */
 	intr_status = get_intr_status(dev);
 	if ((intr_status & IntrTxErrSummary) == 0) {
-		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
+		writew(CmdTxDemand | rp->chip_cmd, dev->base_addr + ChipCmd);
 	}
 	IOSYNC;
 
-	if (np->cur_tx == np->dirty_tx + TX_QUEUE_LEN)
+	if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN)
 		netif_stop_queue(dev);
 
 	dev->trans_start = jiffies;
 
-	spin_unlock_irq (&np->lock);
+	spin_unlock_irq(&rp->lock);
 
 	if (debug > 4) {
 		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-			   dev->name, np->cur_tx-1, entry);
+		       dev->name, rp->cur_tx-1, entry);
 	}
 	return 0;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
-static irqreturn_t via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct net_device *dev = dev_instance;
 	long ioaddr;
@@ -1378,11 +1387,11 @@
 
 		if (debug > 4)
 			printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n",
-				   dev->name, intr_status);
+			       dev->name, intr_status);
 
 		if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
-						   IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
-			via_rhine_rx(dev);
+		    IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
+			rhine_rx(dev);
 
 		if (intr_status & (IntrTxErrSummary | IntrTxDone)) {
 			if (intr_status & IntrTxErrSummary) {
@@ -1391,140 +1400,147 @@
 				while ((readw(ioaddr+ChipCmd) & CmdTxOn) && --cnt)
 					udelay(5);
 				if (debug > 2 && !cnt)
-					printk(KERN_WARNING "%s: via_rhine_interrupt() "
-						   "Tx engine still on.\n",
-						   dev->name);
+					printk(KERN_WARNING "%s: "
+					       "rhine_interrupt() Tx engine"
+					       "still on.\n", dev->name);
 			}
-			via_rhine_tx(dev);
+			rhine_tx(dev);
 		}
 
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & (IntrPCIErr | IntrLinkChange |
 				   IntrStatsMax | IntrTxError | IntrTxAborted |
 				   IntrTxUnderrun | IntrTxDescRace))
-			via_rhine_error(dev, intr_status);
+			rhine_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
 			printk(KERN_WARNING "%s: Too much work at interrupt, "
-				   "status=%#8.8x.\n",
-				   dev->name, intr_status);
+			       "status=%#8.8x.\n",
+			       dev->name, intr_status);
 			break;
 		}
 	}
 
 	if (debug > 3)
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%8.8x.\n",
-			   dev->name, readw(ioaddr + IntrStatus));
+		       dev->name, readw(ioaddr + IntrStatus));
 	return IRQ_RETVAL(handled);
 }
 
 /* This routine is logically part of the interrupt handler, but isolated
    for clarity. */
-static void via_rhine_tx(struct net_device *dev)
+static void rhine_tx(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
-	int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE;
+	struct rhine_private *rp = netdev_priv(dev);
+	int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE;
 
-	spin_lock (&np->lock);
+	spin_lock(&rp->lock);
 
 	/* find and cleanup dirty tx descriptors */
-	while (np->dirty_tx != np->cur_tx) {
-		txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
+	while (rp->dirty_tx != rp->cur_tx) {
+		txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
 		if (debug > 6)
 			printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
-				   entry, txstatus);
+			       entry, txstatus);
 		if (txstatus & DescOwn)
 			break;
 		if (txstatus & 0x8000) {
 			if (debug > 1)
-				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-					   dev->name, txstatus);
-			np->stats.tx_errors++;
-			if (txstatus & 0x0400) np->stats.tx_carrier_errors++;
-			if (txstatus & 0x0200) np->stats.tx_window_errors++;
-			if (txstatus & 0x0100) np->stats.tx_aborted_errors++;
-			if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;
-			if (((np->chip_id == VT86C100A) && txstatus & 0x0002) ||
-				(txstatus & 0x0800) || (txstatus & 0x1000)) {
-				np->stats.tx_fifo_errors++;
-				np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
+				printk(KERN_DEBUG "%s: Transmit error, "
+				       "Tx status %8.8x.\n",
+				       dev->name, txstatus);
+			rp->stats.tx_errors++;
+			if (txstatus & 0x0400) rp->stats.tx_carrier_errors++;
+			if (txstatus & 0x0200) rp->stats.tx_window_errors++;
+			if (txstatus & 0x0100) rp->stats.tx_aborted_errors++;
+			if (txstatus & 0x0080) rp->stats.tx_heartbeat_errors++;
+			if (((rp->chip_id == VT86C100A) && txstatus & 0x0002) ||
+			    (txstatus & 0x0800) || (txstatus & 0x1000)) {
+				rp->stats.tx_fifo_errors++;
+				rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
 				break; /* Keep the skb - we try again */
 			}
 			/* Transmitter restarted in 'abnormal' handler. */
 		} else {
-			if (np->chip_id == VT86C100A)
-				np->stats.collisions += (txstatus >> 3) & 0x0F;
+			if (rp->chip_id == VT86C100A)
+				rp->stats.collisions += (txstatus >> 3) & 0x0F;
 			else
-				np->stats.collisions += txstatus & 0x0F;
+				rp->stats.collisions += txstatus & 0x0F;
 			if (debug > 6)
 				printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n",
-					(txstatus >> 3) & 0xF,
-					txstatus & 0xF);
-			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-			np->stats.tx_packets++;
+				       (txstatus >> 3) & 0xF,
+				       txstatus & 0xF);
+			rp->stats.tx_bytes += rp->tx_skbuff[entry]->len;
+			rp->stats.tx_packets++;
 		}
 		/* Free the original skb. */
-		if (np->tx_skbuff_dma[entry]) {
-			pci_unmap_single(np->pdev,
-							 np->tx_skbuff_dma[entry],
-							 np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+		if (rp->tx_skbuff_dma[entry]) {
+			pci_unmap_single(rp->pdev,
+					 rp->tx_skbuff_dma[entry],
+					 rp->tx_skbuff[entry]->len,
+					 PCI_DMA_TODEVICE);
 		}
-		dev_kfree_skb_irq(np->tx_skbuff[entry]);
-		np->tx_skbuff[entry] = NULL;
-		entry = (++np->dirty_tx) % TX_RING_SIZE;
+		dev_kfree_skb_irq(rp->tx_skbuff[entry]);
+		rp->tx_skbuff[entry] = NULL;
+		entry = (++rp->dirty_tx) % TX_RING_SIZE;
 	}
-	if ((np->cur_tx - np->dirty_tx) < TX_QUEUE_LEN - 4)
-		netif_wake_queue (dev);
+	if ((rp->cur_tx - rp->dirty_tx) < TX_QUEUE_LEN - 4)
+		netif_wake_queue(dev);
 
-	spin_unlock (&np->lock);
+	spin_unlock(&rp->lock);
 }
 
 /* This routine is logically part of the interrupt handler, but isolated
    for clarity and better register allocation. */
-static void via_rhine_rx(struct net_device *dev)
+static void rhine_rx(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
-	int entry = np->cur_rx % RX_RING_SIZE;
-	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
+	struct rhine_private *rp = netdev_priv(dev);
+	int entry = rp->cur_rx % RX_RING_SIZE;
+	int boguscnt = rp->dirty_rx + RX_RING_SIZE - rp->cur_rx;
 
 	if (debug > 4) {
-		printk(KERN_DEBUG "%s: via_rhine_rx(), entry %d status %8.8x.\n",
-			   dev->name, entry, le32_to_cpu(np->rx_head_desc->rx_status));
+		printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n",
+		       dev->name, entry,
+		       le32_to_cpu(rp->rx_head_desc->rx_status));
 	}
 
 	/* If EOP is set on the next entry, it's a new packet. Send it up. */
-	while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {
-		struct rx_desc *desc = np->rx_head_desc;
+	while (!(rp->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {
+		struct rx_desc *desc = rp->rx_head_desc;
 		u32 desc_status = le32_to_cpu(desc->rx_status);
 		int data_size = desc_status >> 16;
 
 		if (debug > 4)
-			printk(KERN_DEBUG "  via_rhine_rx() status is %8.8x.\n",
-				   desc_status);
+			printk(KERN_DEBUG " rhine_rx() status is %8.8x.\n",
+			       desc_status);
 		if (--boguscnt < 0)
 			break;
-		if ( (desc_status & (RxWholePkt | RxErr)) !=  RxWholePkt) {
-			if ((desc_status & RxWholePkt) !=  RxWholePkt) {
-				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-					   "multiple buffers, entry %#x length %d status %8.8x!\n",
-					   dev->name, entry, data_size, desc_status);
-				printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",
-					   dev->name, np->rx_head_desc, &np->rx_ring[entry]);
-				np->stats.rx_length_errors++;
+		if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
+			if ((desc_status & RxWholePkt) != RxWholePkt) {
+				printk(KERN_WARNING "%s: Oversized Ethernet "
+				       "frame spanned multiple buffers, entry "
+				       "%#x length %d status %8.8x!\n",
+				       dev->name, entry, data_size,
+				       desc_status);
+				printk(KERN_WARNING "%s: Oversized Ethernet "
+				       "frame %p vs %p.\n", dev->name,
+				       rp->rx_head_desc, &rp->rx_ring[entry]);
+				rp->stats.rx_length_errors++;
 			} else if (desc_status & RxErr) {
 				/* There was a error. */
 				if (debug > 2)
-					printk(KERN_DEBUG "  via_rhine_rx() Rx error was %8.8x.\n",
-						   desc_status);
-				np->stats.rx_errors++;
-				if (desc_status & 0x0030) np->stats.rx_length_errors++;
-				if (desc_status & 0x0048) np->stats.rx_fifo_errors++;
-				if (desc_status & 0x0004) np->stats.rx_frame_errors++;
+					printk(KERN_DEBUG " rhine_rx() Rx "
+					       "error was %8.8x.\n",
+					       desc_status);
+				rp->stats.rx_errors++;
+				if (desc_status & 0x0030) rp->stats.rx_length_errors++;
+				if (desc_status & 0x0048) rp->stats.rx_fifo_errors++;
+				if (desc_status & 0x0004) rp->stats.rx_frame_errors++;
 				if (desc_status & 0x0002) {
 					/* this can also be updated outside the interrupt handler */
-					spin_lock (&np->lock);
-					np->stats.rx_crc_errors++;
-					spin_unlock (&np->lock);
+					spin_lock(&rp->lock);
+					rp->stats.rx_crc_errors++;
+					spin_unlock(&rp->lock);
 				}
 			}
 		} else {
@@ -1532,76 +1548,89 @@
 			/* Length should omit the CRC */
 			int pkt_len = data_size - 4;
 
-			/* Check if the packet is long enough to accept without copying
-			   to a minimally-sized skbuff. */
+			/* Check if the packet is long enough to accept without
+			   copying to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak &&
 				(skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single_for_cpu(np->pdev, np->rx_skbuff_dma[entry],
-						    np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
-				/* *_IP_COPYSUM isn't defined anywhere and eth_copy_and_sum
-				   is memcpy for all archs so this is kind of pointless right
-				   now ... or? */
-#if HAS_IP_COPYSUM                     /* Call copy + cksum if available. */
-				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+				pci_dma_sync_single_for_cpu(rp->pdev,
+							    rp->rx_skbuff_dma[entry],
+							    rp->rx_buf_sz,
+							    PCI_DMA_FROMDEVICE);
+
+				/* *_IP_COPYSUM isn't defined anywhere and
+				   eth_copy_and_sum is memcpy for all archs so
+				   this is kind of pointless right now
+				   ... or? */
+#if HAS_IP_COPYSUM		/* Call copy + cksum if available. */
+				eth_copy_and_sum(skb,
+						 rp->rx_skbuff[entry]->tail,
+						 pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
-				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-					   pkt_len);
+				memcpy(skb_put(skb, pkt_len),
+				       rp->rx_skbuff[entry]->tail, pkt_len);
 #endif
-				pci_dma_sync_single_for_device(np->pdev, np->rx_skbuff_dma[entry],
-						    np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+				pci_dma_sync_single_for_device(rp->pdev,
+							       rp->rx_skbuff_dma[entry],
+							       rp->rx_buf_sz,
+							       PCI_DMA_FROMDEVICE);
 			} else {
-				skb = np->rx_skbuff[entry];
+				skb = rp->rx_skbuff[entry];
 				if (skb == NULL) {
-					printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",
-						   dev->name);
+					printk(KERN_ERR "%s: Inconsistent Rx "
+					       "descriptor chain.\n",
+					       dev->name);
 					break;
 				}
-				np->rx_skbuff[entry] = NULL;
+				rp->rx_skbuff[entry] = NULL;
 				skb_put(skb, pkt_len);
-				pci_unmap_single(np->pdev, np->rx_skbuff_dma[entry],
-								 np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+				pci_unmap_single(rp->pdev,
+						 rp->rx_skbuff_dma[entry],
+						 rp->rx_buf_sz,
+						 PCI_DMA_FROMDEVICE);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			np->stats.rx_bytes += pkt_len;
-			np->stats.rx_packets++;
+			rp->stats.rx_bytes += pkt_len;
+			rp->stats.rx_packets++;
 		}
-		entry = (++np->cur_rx) % RX_RING_SIZE;
-		np->rx_head_desc = &np->rx_ring[entry];
+		entry = (++rp->cur_rx) % RX_RING_SIZE;
+		rp->rx_head_desc = &rp->rx_ring[entry];
 	}
 
 	/* Refill the Rx ring buffers. */
-	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+	for (; rp->cur_rx - rp->dirty_rx > 0; rp->dirty_rx++) {
 		struct sk_buff *skb;
-		entry = np->dirty_rx % RX_RING_SIZE;
-		if (np->rx_skbuff[entry] == NULL) {
-			skb = dev_alloc_skb(np->rx_buf_sz);
-			np->rx_skbuff[entry] = skb;
+		entry = rp->dirty_rx % RX_RING_SIZE;
+		if (rp->rx_skbuff[entry] == NULL) {
+			skb = dev_alloc_skb(rp->rx_buf_sz);
+			rp->rx_skbuff[entry] = skb;
 			if (skb == NULL)
-				break;			/* Better luck next round. */
-			skb->dev = dev;			/* Mark as being used by this device. */
-			np->rx_skbuff_dma[entry] =
-				pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
-							   PCI_DMA_FROMDEVICE);
-			np->rx_ring[entry].addr = cpu_to_le32(np->rx_skbuff_dma[entry]);
+				break;	/* Better luck next round. */
+			skb->dev = dev;	/* Mark as being used by this device. */
+			rp->rx_skbuff_dma[entry] =
+				pci_map_single(rp->pdev, skb->tail,
+					       rp->rx_buf_sz,
+					       PCI_DMA_FROMDEVICE);
+			rp->rx_ring[entry].addr = cpu_to_le32(rp->rx_skbuff_dma[entry]);
 		}
-		np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
+		rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
 	}
 
 	/* Pre-emptively restart Rx engine. */
 	writew(readw(dev->base_addr + ChipCmd) | CmdRxOn | CmdRxDemand,
-		   dev->base_addr + ChipCmd);
+	       dev->base_addr + ChipCmd);
 }
 
-/* Clears the "tally counters" for CRC errors and missed frames(?).
-   It has been reported that some chips need a write of 0 to clear
-   these, for others the counters are set to 1 when written to and
-   instead cleared when read. So we clear them both ways ... */
+/*
+ * Clears the "tally counters" for CRC errors and missed frames(?).
+ * It has been reported that some chips need a write of 0 to clear
+ * these, for others the counters are set to 1 when written to and
+ * instead cleared when read. So we clear them both ways ...
+ */
 static inline void clear_tally_counters(const long ioaddr)
 {
 	writel(0, ioaddr + RxMissed);
@@ -1609,10 +1638,10 @@
 	readw(ioaddr + RxMissed);
 }
 
-static void via_rhine_restart_tx(struct net_device *dev) {
-	struct netdev_private *np = dev->priv;
+static void rhine_restart_tx(struct net_device *dev) {
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
-	int entry = np->dirty_tx % TX_RING_SIZE;
+	int entry = rp->dirty_tx % TX_RING_SIZE;
 	u32 intr_status;
 
 	/*
@@ -1624,120 +1653,123 @@
 	if ((intr_status & IntrTxErrSummary) == 0) {
 
 		/* We know better than the chip where it should continue. */
-		writel(np->tx_ring_dma + entry * sizeof(struct tx_desc),
-			   ioaddr + TxRingPtr);
+		writel(rp->tx_ring_dma + entry * sizeof(struct tx_desc),
+		       ioaddr + TxRingPtr);
 
-		writew(CmdTxDemand | np->chip_cmd, ioaddr + ChipCmd);
+		writew(CmdTxDemand | rp->chip_cmd, ioaddr + ChipCmd);
 		IOSYNC;
 	}
 	else {
 		/* This should never happen */
 		if (debug > 1)
-			printk(KERN_WARNING "%s: via_rhine_restart_tx() "
-				   "Another error occured %8.8x.\n",
-				   dev->name, intr_status);
+			printk(KERN_WARNING "%s: rhine_restart_tx() "
+			       "Another error occured %8.8x.\n",
+			       dev->name, intr_status);
 	}
 
 }
 
-static void via_rhine_error(struct net_device *dev, int intr_status)
+static void rhine_error(struct net_device *dev, int intr_status)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
-	spin_lock (&np->lock);
+	spin_lock(&rp->lock);
 
 	if (intr_status & (IntrLinkChange)) {
 		if (readb(ioaddr + MIIStatus) & 0x02) {
 			/* Link failed, restart autonegotiation. */
-			if (np->drv_flags & HasDavicomPhy)
-				mdio_write(dev, np->phys[0], MII_BMCR, 0x3300);
+			if (rp->drv_flags & HasDavicomPhy)
+				mdio_write(dev, rp->phys[0], MII_BMCR, 0x3300);
 		} else
-			via_rhine_check_duplex(dev);
+			rhine_check_duplex(dev);
 		if (debug)
-			printk(KERN_ERR "%s: MII status changed: Autonegotiation "
-				   "advertising %4.4x  partner %4.4x.\n", dev->name,
-			   mdio_read(dev, np->phys[0], MII_ADVERTISE),
-			   mdio_read(dev, np->phys[0], MII_LPA));
+			printk(KERN_ERR "%s: MII status changed: "
+			       "Autonegotiation advertising %4.4x partner "
+			       "%4.4x.\n", dev->name,
+			       mdio_read(dev, rp->phys[0], MII_ADVERTISE),
+			       mdio_read(dev, rp->phys[0], MII_LPA));
 	}
 	if (intr_status & IntrStatsMax) {
-		np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
-		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
+		rp->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs);
+		rp->stats.rx_missed_errors += readw(ioaddr + RxMissed);
 		clear_tally_counters(ioaddr);
 	}
 	if (intr_status & IntrTxAborted) {
 		if (debug > 1)
 			printk(KERN_INFO "%s: Abort %8.8x, frame dropped.\n",
-				   dev->name, intr_status);
+			       dev->name, intr_status);
 	}
 	if (intr_status & IntrTxUnderrun) {
-		if (np->tx_thresh < 0xE0)
-			writeb(np->tx_thresh += 0x20, ioaddr + TxConfig);
+		if (rp->tx_thresh < 0xE0)
+			writeb(rp->tx_thresh += 0x20, ioaddr + TxConfig);
 		if (debug > 1)
 			printk(KERN_INFO "%s: Transmitter underrun, Tx "
-				   "threshold now %2.2x.\n",
-				   dev->name, np->tx_thresh);
+			       "threshold now %2.2x.\n",
+			       dev->name, rp->tx_thresh);
 	}
 	if (intr_status & IntrTxDescRace) {
 		if (debug > 2)
 			printk(KERN_INFO "%s: Tx descriptor write-back race.\n",
-				   dev->name);
+			       dev->name);
 	}
-	if ((intr_status & IntrTxError) && ~( IntrTxAborted | IntrTxUnderrun |
-										   IntrTxDescRace )) {
-		if (np->tx_thresh < 0xE0) {
-			writeb(np->tx_thresh += 0x20, ioaddr + TxConfig);
+	if ((intr_status & IntrTxError) &&
+	    (intr_status & (IntrTxAborted |
+	     IntrTxUnderrun | IntrTxDescRace)) == 0) {
+		if (rp->tx_thresh < 0xE0) {
+			writeb(rp->tx_thresh += 0x20, ioaddr + TxConfig);
 		}
 		if (debug > 1)
 			printk(KERN_INFO "%s: Unspecified error. Tx "
-				   "threshold now %2.2x.\n",
-				   dev->name, np->tx_thresh);
+			       "threshold now %2.2x.\n",
+			       dev->name, rp->tx_thresh);
 	}
-	if (intr_status & ( IntrTxAborted | IntrTxUnderrun | IntrTxDescRace |
-						IntrTxError ))
-		via_rhine_restart_tx(dev);
-
-	if (intr_status & ~( IntrLinkChange | IntrStatsMax | IntrTxUnderrun |
-						 IntrTxError | IntrTxAborted | IntrNormalSummary |
-						 IntrTxDescRace )) {
+	if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace |
+			   IntrTxError))
+		rhine_restart_tx(dev);
+
+	if (intr_status & ~(IntrLinkChange | IntrStatsMax | IntrTxUnderrun |
+			    IntrTxError | IntrTxAborted | IntrNormalSummary |
+			    IntrTxDescRace)) {
 		if (debug > 1)
-			printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n",
-				   dev->name, intr_status);
+			printk(KERN_ERR "%s: Something Wicked happened! "
+			       "%8.8x.\n", dev->name, intr_status);
 	}
 
-	spin_unlock (&np->lock);
+	spin_unlock(&rp->lock);
 }
 
-static struct net_device_stats *via_rhine_get_stats(struct net_device *dev)
+static struct net_device_stats *rhine_get_stats(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	unsigned long flags;
 
-	spin_lock_irqsave(&np->lock, flags);
-	np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
-	np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
+	spin_lock_irqsave(&rp->lock, flags);
+	rp->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs);
+	rp->stats.rx_missed_errors += readw(ioaddr + RxMissed);
 	clear_tally_counters(ioaddr);
-	spin_unlock_irqrestore(&np->lock, flags);
+	spin_unlock_irqrestore(&rp->lock, flags);
 
-	return &np->stats;
+	return &rp->stats;
 }
 
-static void via_rhine_set_rx_mode(struct net_device *dev)
+static void rhine_set_rx_mode(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
-	u32 mc_filter[2];			/* Multicast hash filter */
-	u8 rx_mode;					/* Note: 0x02=accept runt, 0x01=accept errs */
+	u32 mc_filter[2];	/* Multicast hash filter */
+	u8 rx_mode;		/* Note: 0x02=accept runt, 0x01=accept errs */
 
-	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+	if (dev->flags & IFF_PROMISC) {		/* Set promiscuous. */
 		/* Unconditionally log net taps. */
-		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+		       dev->name);
 		rx_mode = 0x1C;
 		writel(0xffffffff, ioaddr + MulticastFilter0);
 		writel(0xffffffff, ioaddr + MulticastFilter1);
 	} else if ((dev->mc_count > multicast_filter_limit)
-			   ||  (dev->flags & IFF_ALLMULTI)) {
+		   || (dev->flags & IFF_ALLMULTI)) {
 		/* Too many to match, or accept all multicasts. */
 		writel(0xffffffff, ioaddr + MulticastFilter0);
 		writel(0xffffffff, ioaddr + MulticastFilter1);
@@ -1747,7 +1779,7 @@
 		int i;
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-			 i++, mclist = mclist->next) {
+		     i++, mclist = mclist->next) {
 			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
 
 			mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
@@ -1756,66 +1788,66 @@
 		writel(mc_filter[1], ioaddr + MulticastFilter1);
 		rx_mode = 0x0C;
 	}
-	writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
+	writeb(rp->rx_thresh | rx_mode, ioaddr + RxConfig);
 }
 
-static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
+static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 
-	strcpy (info->driver, DRV_NAME);
-	strcpy (info->version, DRV_VERSION);
-	strcpy (info->bus_info, pci_name(np->pdev));
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(rp->pdev));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	int rc;
 
-	if (!(np->drv_flags & CanHaveMII))
+	if (!(rp->drv_flags & CanHaveMII))
 		return -EINVAL;
 
-	spin_lock_irq(&np->lock);
-	rc = mii_ethtool_gset(&np->mii_if, cmd);
-	spin_unlock_irq(&np->lock);
+	spin_lock_irq(&rp->lock);
+	rc = mii_ethtool_gset(&rp->mii_if, cmd);
+	spin_unlock_irq(&rp->lock);
 
 	return rc;
 }
 
 static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	int rc;
 
-	if (!(np->drv_flags & CanHaveMII))
+	if (!(rp->drv_flags & CanHaveMII))
 		return -EINVAL;
 
-	spin_lock_irq(&np->lock);
-	rc = mii_ethtool_sset(&np->mii_if, cmd);
-	spin_unlock_irq(&np->lock);
+	spin_lock_irq(&rp->lock);
+	rc = mii_ethtool_sset(&rp->mii_if, cmd);
+	spin_unlock_irq(&rp->lock);
 
 	return rc;
 }
 
 static int netdev_nway_reset(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 
-	if (!(np->drv_flags & CanHaveMII))
+	if (!(rp->drv_flags & CanHaveMII))
 		return -EINVAL;
 
-	return mii_nway_restart(&np->mii_if);
+	return mii_nway_restart(&rp->mii_if);
 }
 
 static u32 netdev_get_link(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 
-	if (!(np->drv_flags & CanHaveMII))
+	if (!(rp->drv_flags & CanHaveMII))
 		return 0;	/* -EINVAL */
 
-	return mii_link_ok(&np->mii_if);
+	return mii_link_ok(&rp->mii_if);
 }
 
 static u32 netdev_get_msglevel(struct net_device *dev)
@@ -1842,37 +1874,38 @@
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
 	int rc;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	spin_lock_irq(&np->lock);
-	rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
-	spin_unlock_irq(&np->lock);
+	spin_lock_irq(&rp->lock);
+	rc = generic_mii_ioctl(&rp->mii_if, data, cmd, NULL);
+	spin_unlock_irq(&rp->lock);
 
 	return rc;
 }
 
-static int via_rhine_close(struct net_device *dev)
+static int rhine_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct rhine_private *rp = netdev_priv(dev);
 
-	del_timer_sync(&np->timer);
+	del_timer_sync(&rp->timer);
 
-	spin_lock_irq(&np->lock);
+	spin_lock_irq(&rp->lock);
 
 	netif_stop_queue(dev);
 
 	if (debug > 1)
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
-			   dev->name, readw(ioaddr + ChipCmd));
+		printk(KERN_DEBUG "%s: Shutting down ethercard, "
+		       "status was %4.4x.\n",
+		       dev->name, readw(ioaddr + ChipCmd));
 
 	/* Switch to loopback mode to avoid hardware races. */
-	writeb(np->tx_thresh | 0x02, ioaddr + TxConfig);
+	writeb(rp->tx_thresh | 0x02, ioaddr + TxConfig);
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	writew(0x0000, ioaddr + IntrEnable);
@@ -1880,9 +1913,9 @@
 	/* Stop the chip's Tx and Rx processes. */
 	writew(CmdStop, ioaddr + ChipCmd);
 
-	spin_unlock_irq(&np->lock);
+	spin_unlock_irq(&rp->lock);
 
-	free_irq(np->pdev->irq, dev);
+	free_irq(rp->pdev->irq, dev);
 	free_rbufs(dev);
 	free_tbufs(dev);
 	free_ring(dev);
@@ -1891,7 +1924,7 @@
 }
 
 
-static void __devexit via_rhine_remove_one (struct pci_dev *pdev)
+static void __devexit rhine_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
@@ -1899,7 +1932,7 @@
 
 	pci_release_regions(pdev);
 
-#ifdef USE_MEM
+#ifdef USE_MMIO
 	iounmap((char *)(dev->base_addr));
 #endif
 
@@ -1909,39 +1942,29 @@
 }
 
 
-static struct pci_driver via_rhine_driver = {
+static struct pci_driver rhine_driver = {
 	.name		= "via-rhine",
-	.id_table	= via_rhine_pci_tbl,
-	.probe		= via_rhine_init_one,
-	.remove		= __devexit_p(via_rhine_remove_one),
+	.id_table	= rhine_pci_tbl,
+	.probe		= rhine_init_one,
+	.remove		= __devexit_p(rhine_remove_one),
 };
 
 
-static int __init via_rhine_init (void)
+static int __init rhine_init(void)
 {
 /* when a module, this is printed whether or not devices are found in probe */
 #ifdef MODULE
 	printk(version);
 #endif
-	return pci_module_init (&via_rhine_driver);
+	return pci_module_init(&rhine_driver);
 }
 
 
-static void __exit via_rhine_cleanup (void)
+static void __exit rhine_cleanup(void)
 {
-	pci_unregister_driver (&via_rhine_driver);
+	pci_unregister_driver(&rhine_driver);
 }
 
 
-module_init(via_rhine_init);
-module_exit(via_rhine_cleanup);
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
+module_init(rhine_init);
+module_exit(rhine_cleanup);
--- diff/drivers/net/wireless/prism54/isl_38xx.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/isl_38xx.c	2004-05-27 18:34:17.000000000 +0100
@@ -1,4 +1,4 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.c,v 1.22 2004/02/28 03:06:07 mcgrof Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.c,v 1.26 2004/03/20 16:58:36 mcgrof Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_
@@ -25,17 +25,11 @@
 #include <linux/types.h>
 #include <linux/delay.h>
 
-#include "isl_38xx.h"
-#include <linux/firmware.h>
-
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#include <linux/config.h>
-#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE)
-#error No Firmware Loading configured in the kernel !
-#endif
-
+#include "prismcompat.h"
+#include "isl_38xx.h"
 #include "islpci_dev.h"
 #include "islpci_mgt.h"
 
--- diff/drivers/net/wireless/prism54/isl_38xx.h	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/isl_38xx.h	2004-05-27 18:34:17.000000000 +0100
@@ -1,4 +1,4 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.h,v 1.22 2004/02/28 03:06:07 mcgrof Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.h,v 1.25 2004/03/20 16:58:36 mcgrof Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *
@@ -22,14 +22,6 @@
 
 #include <linux/version.h>
 #include <asm/io.h>
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,75))
-#include <linux/device.h>
-# define _REQ_FW_DEV_T struct device *
-#else
-# define _REQ_FW_DEV_T char *
-#endif
-
 #include <asm/byteorder.h>
 
 #define ISL38XX_CB_RX_QSIZE                     8
--- diff/drivers/net/wireless/prism54/isl_ioctl.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/isl_ioctl.c	2004-05-27 18:34:17.000000000 +0100
@@ -1,7 +1,7 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.c,v 1.140 2004/02/28 03:06:07 mcgrof Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.c,v 1.154 2004/05/20 06:24:11 ajfa Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
- *            (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *            (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
  *            (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
  *            (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
  *
@@ -25,10 +25,10 @@
 #include <linux/kernel.h>
 #include <linux/if_arp.h>
 #include <linux/pci.h>
-#include <linux/moduleparam.h>
 
 #include <asm/uaccess.h>
 
+#include "prismcompat.h"
 #include "isl_ioctl.h"
 #include "islpci_mgt.h"
 #include "isl_oid.h"		/* additional types and defs for isl38xx fw */
@@ -87,9 +87,9 @@
 
 	/* For now, just catch early the Repeater and Secondary modes here */
 	if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) {
-		printk(KERN_DEBUG "%s(): Sorry, Repeater mode and Secondary mode "
-				"are not yet supported by this driver.\n",
-		       __FUNCTION__);
+		printk(KERN_DEBUG
+		       "%s(): Sorry, Repeater mode and Secondary mode "
+		       "are not yet supported by this driver.\n", __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -143,8 +143,8 @@
 {
 	u32 t;
 	struct obj_buffer psm_buffer = {
-		.size = cpu_to_le32(PSM_BUFFER_SIZE),
-		.addr = cpu_to_le32(priv->device_psm_buffer)
+		.size = PSM_BUFFER_SIZE,
+		.addr = priv->device_psm_buffer
 	};
 
 	mgt_set(priv, DOT11_OID_CHANNEL, &init_channel);
@@ -166,21 +166,13 @@
 	 * for it save old values */
 	if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) {
 		printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. "
-				"Using default mode\n", __FUNCTION__);
+		       "Using default mode\n", __FUNCTION__);
 		init_mode = CARD_DEFAULT_IW_MODE;
 	}
 	/* This sets all of the mode-dependent values */
 	prism54_mib_mode_helper(priv, init_mode);
 }
 
-void
-prism54_mib_init_work(islpci_private *priv)
-{
-	down_write(&priv->mib_sem);
-	mgt_commit(priv);
-	up_write(&priv->mib_sem);
-}
-
 /* this will be executed outside of atomic context thanks to
  * schedule_work(), thus we can as well use sleeping semaphore
  * locking */
@@ -195,16 +187,9 @@
 	if (down_interruptible(&priv->stats_sem))
 		return;
 
-/* missing stats are :
- *  iwstatistics.qual.updated
- *  iwstatistics.discard.nwid	    
- *  iwstatistics.discard.fragment	    
- *  iwstatistics.discard.misc
- *  iwstatistics.miss.beacon */
-
 /* Noise floor.
  * I'm not sure if the unit is dBm.
- * Note : If we are not connected, this value seems to be irrevelant. */
+ * Note : If we are not connected, this value seems to be irrelevant. */
 
 	mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
 	priv->local_iwstatistics.qual.noise = r.u;
@@ -216,8 +201,7 @@
 	data = r.ptr;
 
 	/* copy this MAC to the bss */
-	for (j = 0; j < 6; j++)
-		bss.address[j] = data[j];
+	memcpy(bss.address, data, 6);
 	kfree(data);
 
 	/* now ask for the corresponding bss */
@@ -285,7 +269,7 @@
 	/* Commit in Monitor mode is not necessary, also setting essid
 	 * in Monitor mode does not make sense and isn't allowed for this
 	 * device's firmware */
-	if(priv->iw_mode != IW_MODE_MONITOR)
+	if (priv->iw_mode != IW_MODE_MONITOR)
 		return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL);
 	return 0;
 }
@@ -327,34 +311,15 @@
 {
 	islpci_private *priv = netdev_priv(ndev);
 	int rvalue;
-	u32 c = 0;
+	u32 c;
 
-	/* prepare the structure for the set object */
 	if (fwrq->m < 1000)
-		/* structure value contains a channel indication */
+		/* we have a channel number */
 		c = fwrq->m;
-	else {
-		/* structure contains a frequency indication and fwrq->e = 1 */
-		int f = fwrq->m / 100000;
-
-		if (fwrq->e != 1)
-			return -EINVAL;
-		if ((f >= 2412) && (f <= 2484)) {
-			while ((c < 14) && (f != frequency_list_bg[c]))
-				c++;
-			if (c >= 14)
-				return -EINVAL;
-		} else if ((f >= (int) 5170) && (f <= (int) 5320)) {
-			while ((c < 12) && (f != frequency_list_a[c]))
-				c++;
-			if (c >= 12)
-				return -EINVAL;
-		} else
-			return -EINVAL;
-		c++;
-	}
+	else
+		c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0;
 
-	rvalue = mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c);
+	rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL;
 
 	/* Call commit handler */
 	return (rvalue ? rvalue : -EINPROGRESS);
@@ -410,7 +375,7 @@
 
 	mgt_commit(priv);
 	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
-	    ? ARPHRD_IEEE80211 : ARPHRD_ETHER;
+	    ? priv->monitor_type : ARPHRD_ETHER;
 	up_write(&priv->mib_sem);
 
 	return 0;
@@ -445,7 +410,6 @@
 	/* by default  the card sets this to 20. */
 	sens = vwrq->disabled ? 20 : vwrq->value;
 
-	/* set the ed threshold. */
 	return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens);
 }
 
@@ -524,31 +488,22 @@
 		return 0;
 
 	/* Request the device for the supported frequencies
-	 * not really revelant since some devices will report the 5 GHz band
+	 * not really relevant since some devices will report the 5 GHz band
 	 * frequencies even if they don't support them.
 	 */
 	rvalue =
 	    mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r);
 	freq = r.ptr;
 
-	range->num_channels = le16_to_cpu(freq->nr);
-	range->num_frequency = le16_to_cpu(freq->nr);
+	range->num_channels = freq->nr;
+	range->num_frequency = freq->nr;
 
-	/* Frequencies are not listed in the right order. The reordering is probably
-	 * firmware dependant and thus should work for everyone.
-	 */
-	m = min(IW_MAX_FREQUENCIES, (int) le16_to_cpu(freq->nr));
-	for (i = 0; i < m - 12; i++) {
-		range->freq[i].m = le16_to_cpu(freq->mhz[12 + i]);
-		range->freq[i].e = 6;
-		range->freq[i].i = i + 1;
-	}
-	for (i = m - 12; i < m; i++) {
-		range->freq[i].m = le16_to_cpu(freq->mhz[i - m + 12]);
+	m = min(IW_MAX_FREQUENCIES, (int) freq->nr);
+	for (i = 0; i < m; i++) {
+		range->freq[i].m = freq->mhz[i];
 		range->freq[i].e = 6;
-		range->freq[i].i = i + 23;
+		range->freq[i].i = channel_of_freq(freq->mhz[i]);
 	}
-
 	kfree(freq);
 
 	rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
@@ -563,9 +518,7 @@
 		i++;
 		data++;
 	}
-
 	range->num_bitrates = i;
-
 	kfree(r.ptr);
 
 	return rvalue;
@@ -604,7 +557,6 @@
 	int rvalue;
 
 	rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
-
 	memcpy(awrq->sa_data, r.ptr, 6);
 	awrq->sa_family = ARPHRD_ETHER;
 	kfree(r.ptr);
@@ -655,7 +607,7 @@
 #define CAP_CRYPT 0x10
 
 	/* Mode */
-	cap = le16_to_cpu(bss->capinfo);
+	cap = bss->capinfo;
 	iwe.u.mode = 0;
 	if (cap & CAP_ESS)
 		iwe.u.mode = IW_MODE_MASTER;
@@ -677,8 +629,8 @@
 	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
 
 	/* Add frequency. (short) bss->channel is the frequency in MHz */
-	iwe.u.freq.m = bss->channel;
-	iwe.u.freq.e = 6;
+	iwe.u.freq.m = channel_of_freq(bss->channel);
+	iwe.u.freq.e = 0;
 	iwe.cmd = SIOCGIWFREQ;
 	current_ev =
 	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
@@ -714,7 +666,6 @@
 			kfree(buf);
 		}
 	}
-
 	return current_ev;
 }
 
@@ -741,13 +692,13 @@
 
 	/* Ask the device for a list of known bss. We can report at most
 	 * IW_MAX_AP=64 to the range struct. But the device won't repport anything
-	 * if you change the value of MAXBSS=24. Anyway 24 AP It is probably enough.
+	 * if you change the value of IWMAX_BSS=24.
 	 */
 	rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
 	bsslist = r.ptr;
 
 	/* ok now, scan the list and translate its info */
-	for (i = 0; i < min(IW_MAX_AP, (int) le32_to_cpu(bsslist->nr)); i++)
+	for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
 		current_ev = prism54_translate_bss(ndev, current_ev,
 						   extra + IW_SCAN_MAX_DATA,
 						   &(bsslist->bsslist[i]),
@@ -776,7 +727,7 @@
 		memcpy(essid.octets, extra, dwrq->length);
 	} else
 		essid.length = 0;
-	
+
 	if (priv->iw_mode != IW_MODE_MONITOR)
 		return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid);
 
@@ -862,38 +813,39 @@
 	char *data;
 	int ret, i;
 	union oid_res_t r;
-	
+
 	if (vwrq->value == -1) {
 		/* auto mode. No limit. */
 		profile = 1;
 		return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
 	}
-	
-	if((ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r)))
+
+	if ((ret =
+	     mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r)))
 		return ret;
-		
+
 	rate = (u32) (vwrq->value / 500000);
 	data = r.ptr;
 	i = 0;
-	
-	while(data[i]) {
-		if(rate && (data[i] == rate)) {
+
+	while (data[i]) {
+		if (rate && (data[i] == rate)) {
 			break;
 		}
-		if(vwrq->value == i) {
+		if (vwrq->value == i) {
 			break;
 		}
 		data[i] |= 0x80;
 		i++;
 	}
-		
-	if(!data[i]) {
+
+	if (!data[i]) {
 		return -EINVAL;
 	}
-	
+
 	data[i] |= 0x80;
 	data[i + 1] = 0;
-	
+
 	/* Now, check if we want a fixed or auto value */
 	if (vwrq->fixed) {
 		data[0] = data[i];
@@ -908,14 +860,14 @@
 		i++;
 	}
 	printk("0\n");
-*/	
+*/
 	profile = -1;
 	ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
 	ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data);
 	ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data);
-	
+
 	kfree(r.ptr);
-	
+
 	return ret;
 }
 
@@ -931,17 +883,17 @@
 	union oid_res_t r;
 
 	/* Get the current bit rate */
-	if((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r)))
+	if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r)))
 		return rvalue;
 	vwrq->value = r.u * 500000;
 
 	/* request the device for the enabled rates */
-	if((rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r)))
+	if ((rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r)))
 		return rvalue;
 	data = r.ptr;
 	vwrq->fixed = (data[0] != 0) && (data[1] == 0);
 	kfree(r.ptr);
-	
+
 	return 0;
 }
 
@@ -997,8 +949,6 @@
  * small frame <=>  smaller than the rts threshold
  * This is not really the behavior expected by the wireless tool but it seems
  * to be a common behavior in other drivers.
- * 
- * It seems that playing with this tends to hang the card -> DISABLED
  */
 
 static int
@@ -1030,18 +980,16 @@
 		lifetime = vwrq->value / 1024;
 
 	/* now set what is requested */
-
-	if (slimit != 0)
+	if (slimit)
 		rvalue =
 		    mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit);
-	if (llimit != 0)
+	if (llimit)
 		rvalue |=
 		    mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit);
-	if (lifetime != 0)
+	if (lifetime)
 		rvalue |=
 		    mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0,
 				    &lifetime);
-
 	return rvalue;
 }
 
@@ -1137,8 +1085,7 @@
 			}
 		}
 	}
-
-	/* now read the flags     */
+	/* now read the flags */
 	if (dwrq->flags & IW_ENCODE_DISABLED) {
 		/* Encoding disabled, 
 		 * authen = DOT11_AUTH_OS;
@@ -1225,7 +1172,7 @@
 
 	rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r);
 	/* intersil firmware operates in 0.25 dBm (1/4 dBm) */
-	vwrq->value = (s32)r.u / 4;
+	vwrq->value = (s32) r.u / 4;
 	vwrq->fixed = 1;
 	/* radio is not turned of
 	 * btw: how is possible to turn off only the radio 
@@ -1271,28 +1218,36 @@
 }
 
 static int
-prism54_set_beacon(struct net_device *ndev, struct iw_request_info *info,
-		   __u32 * uwrq, char *extra)
+prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_point *dwrq, char *extra)
 {
-	int rvalue = mgt_set_request((islpci_private *) netdev_priv(ndev),
-				     DOT11_OID_BEACONPERIOD, 0, uwrq);
+	union oid_res_t r;
+	int rvalue;
+	enum oid_num_t n = dwrq->flags;
 
-	return (rvalue ? rvalue : -EINPROGRESS);
+	rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r);
+	dwrq->length = mgt_response_to_str(n, &r, extra);
+	if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
+		kfree(r.ptr);
+	return rvalue;
 }
 
 static int
-prism54_get_beacon(struct net_device *ndev, struct iw_request_info *info,
-		   __u32 * uwrq, char *extra)
+prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
+		__u32 * uwrq, char *extra)
 {
-	union oid_res_t r;
-	int rvalue;
+	u32 oid = uwrq[0], u = uwrq[1];
 
-	rvalue =
-	    mgt_get_request((islpci_private *) netdev_priv(ndev),
-			    DOT11_OID_BEACONPERIOD, 0, NULL, &r);
-	*uwrq = r.u;
+	return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u);
+}
 
-	return rvalue;
+static int
+prism54_set_raw(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_point *dwrq, char *extra)
+{
+	u32 oid = dwrq->flags;
+
+	return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra);
 }
 
 void
@@ -1511,8 +1466,9 @@
 		return -ENOMEM;
 
 	/* Tell the card to kick every client */
-	mlme->id = cpu_to_le16(0);
-	rvalue = mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
+	mlme->id = 0;
+	rvalue =
+	    mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
 	kfree(mlme);
 
 	return rvalue;
@@ -1535,8 +1491,9 @@
 
 	/* Tell the card to only kick the corresponding bastard */
 	memcpy(mlme->address, addr->sa_data, ETH_ALEN);
-	mlme->id = cpu_to_le16(-1);
-	rvalue = mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
+	mlme->id = -1;
+	rvalue =
+	    mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
 
 	kfree(mlme);
 
@@ -1551,12 +1508,12 @@
 {
 	const u8 *a = mlme->address;
 	int n = snprintf(dest, IW_CUSTOM_MAX,
-			 "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s",
+			 "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)",
 			 str,
-			 ((priv->iw_mode == IW_MODE_MASTER) ? "to" : "from"),
+			 ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
 			 a[0], a[1], a[2], a[3], a[4], a[5],
 			 (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
-			  : ""));
+			  : ""), mlme->code);
 	BUG_ON(n > IW_CUSTOM_MAX);
 	*length = n;
 }
@@ -1598,14 +1555,15 @@
 {
 	islpci_private *priv = netdev_priv(ndev);
 
-	if (le32_to_cpu(bitrate)) {
+	if (bitrate) {
 		if (priv->iw_mode == IW_MODE_INFRA) {
 			union iwreq_data uwrq;
 			prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,
 					NULL);
 			wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
 		} else
-			send_simple_event(netdev_priv(ndev), "Link established");
+			send_simple_event(netdev_priv(ndev),
+					  "Link established");
 	} else
 		send_simple_event(netdev_priv(ndev), "Link lost");
 }
@@ -1765,15 +1723,14 @@
 static void
 handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid)
 {
-	if (((le16_to_cpu(mlme->state) == DOT11_STATE_AUTHING) ||
-	     (le16_to_cpu(mlme->state) == DOT11_STATE_ASSOCING))
+	if (((mlme->state == DOT11_STATE_AUTHING) ||
+	     (mlme->state == DOT11_STATE_ASSOCING))
 	    && mgt_mlme_answer(priv)) {
 		/* Someone is requesting auth and we must respond. Just send back
 		 * the trap with error code set accordingly.
 		 */
-		mlme->code = cpu_to_le16(prism54_mac_accept(&priv->acl,
-							    mlme->
-							    address) ? 0 : 1);
+		mlme->code = prism54_mac_accept(&priv->acl,
+						mlme->address) ? 0 : 1;
 		mgt_set_request(priv, oid, 0, mlme);
 	}
 }
@@ -1797,6 +1754,13 @@
 	 * suited. We use the more flexible custom event facility.
 	 */
 
+	/* I fear prism54_process_bss_data won't work with big endian data */
+	if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
+		prism54_process_bss_data(priv, oid, mlme->address,
+					 payload, len);
+
+	mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
+
 	switch (oid) {
 
 	case GEN_OID_LINKSTATE:
@@ -1831,8 +1795,6 @@
 		break;
 
 	case DOT11_OID_BEACON:
-		prism54_process_bss_data(priv, oid, mlme->address,
-					 payload, len);
 		send_formatted_event(priv,
 				     "Received a beacon from an unkown AP",
 				     mlme, 0);
@@ -1840,15 +1802,11 @@
 
 	case DOT11_OID_PROBE:
 		/* we received a probe from a client. */
-		prism54_process_bss_data(priv, oid, mlme->address,
-					 payload, len);
 		send_formatted_event(priv, "Received a probe from client", mlme,
 				     0);
 		break;
 
-		/* Note : the following should never happen since we don't run the card in
-		 * extended mode.
-		 * Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
+		/* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
 		 * is backward compatible layout-wise with "struct obj_mlme".
 		 */
 
@@ -1893,7 +1851,8 @@
 	struct net_device *ndev = frame->ndev;
 	enum oid_num_t n = mgt_oidtonum(frame->header->oid);
 
-	prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
+	if (n != OID_NUM_LAST)
+		prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
 	islpci_mgt_release(frame);
 }
 
@@ -1915,13 +1874,6 @@
 }
 
 int
-prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
-{
-	/* should we really support this old stuff ? */
-	return -EOPNOTSUPP;
-}
-
-int
 prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
 		__u32 * uwrq, char *extra)
 {
@@ -1951,65 +1903,33 @@
 }
 
 int
-prism54_set_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
-		__u32 *uwrq, char *extra)
+prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
+		     __u32 * uwrq, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	u32 max_burst;
-
-	max_burst = (*uwrq) ? *uwrq : CARD_DEFAULT_MAXFRAMEBURST;
-	mgt_set_request(priv, DOT11_OID_MAXFRAMEBURST, 0, &max_burst);
-
-	return -EINPROGRESS; /* Call commit handler */
-}
+	priv->monitor_type =
+	    (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211);
+	if (priv->iw_mode == IW_MODE_MONITOR)
+		priv->ndev->type = priv->monitor_type;
 
-int
-prism54_get_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
-		__u32 *uwrq, char *extra)
-{
-	islpci_private *priv = netdev_priv(ndev);
-	union oid_res_t r;
-	int rvalue;
-	
-	rvalue = mgt_get_request(priv, DOT11_OID_MAXFRAMEBURST, 0, NULL, &r);
-	*uwrq = r.u;
-	
-	return rvalue;
+	return 0;
 }
 
 int
-prism54_set_profile(struct net_device *ndev, struct iw_request_info *info,
-		__u32 *uwrq, char *extra)
+prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
+		     __u32 * uwrq, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	u32 profile;
-
-	profile = (*uwrq) ? *uwrq : CARD_DEFAULT_PROFILE;
-	mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
-	
-	return -EINPROGRESS; /* Call commit handler */
+	*uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM);
+	return 0;
 }
 
 int
-prism54_get_profile(struct net_device *ndev, struct iw_request_info *info,
-		__u32 *uwrq, char *extra)
+prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
+		  __u32 * uwrq, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	union oid_res_t r;
-	int rvalue;
-
-	rvalue = mgt_get_request(priv, DOT11_OID_PROFILES, 0, NULL, &r);
-	*uwrq = r.u;
 
-	return rvalue;
-}
-
-int
-prism54_oid(struct net_device *ndev, struct iw_request_info *info,
-		__u32 *uwrq, char *extra)
-{
-	islpci_private *priv = netdev_priv(ndev);
-	
 	priv->priv_oid = *uwrq;
 	printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
 
@@ -2017,22 +1937,26 @@
 }
 
 int
-prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
-		struct iw_point *data, char *extra)
+prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
+		      struct iw_point *data, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
 	struct islpci_mgmtframe *response = NULL;
 	int ret = -EIO, response_op = PIMFOR_OP_ERROR;
-	
+
 	printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
 	data->length = 0;
-	
+
 	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
-		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, priv->priv_oid, extra, 256, &response);
+		ret =
+		    islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
+					   priv->priv_oid, extra, 256,
+					   &response);
 		response_op = response->header->operation;
 		printk("%s: ret: %i\n", ndev->name, ret);
 		printk("%s: response_op: %i\n", ndev->name, response_op);
-		if (ret || !response || response->header->operation == PIMFOR_OP_ERROR) {
+		if (ret || !response
+		    || response->header->operation == PIMFOR_OP_ERROR) {
 			if (response) {
 				islpci_mgt_release(response);
 			}
@@ -2046,35 +1970,65 @@
 			printk("%s: len: %i\n", ndev->name, data->length);
 		}
 	}
-	
+
 	return ret;
 }
 
 int
-prism54_set_oid(struct net_device *ndev, struct iw_request_info *info,
-		struct iw_point *data, char *extra)
+prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
+		      struct iw_point *data, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
 	struct islpci_mgmtframe *response = NULL;
 	int ret = 0, response_op = PIMFOR_OP_ERROR;
-	
-	printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, data->length);
-	
+
+	printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
+	       data->length);
+
 	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
-		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, priv->priv_oid, extra, data->length, &response);
+		ret =
+		    islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
+					   priv->priv_oid, extra, data->length,
+					   &response);
 		printk("%s: ret: %i\n", ndev->name, ret);
 		if (!ret) {
 			response_op = response->header->operation;
-			printk("%s: response_op: %i\n", ndev->name, response_op);
+			printk("%s: response_op: %i\n", ndev->name,
+			       response_op);
 			islpci_mgt_release(response);
 		}
 		if (ret || response_op == PIMFOR_OP_ERROR) {
 			printk("%s: EIO\n", ndev->name);
-		        ret = -EIO;
+			ret = -EIO;
 		}
 	}
-	
-	return ret;
+
+	return (ret ? ret : -EINPROGRESS);
+}
+
+static int
+prism54_set_spy(struct net_device *ndev,
+		struct iw_request_info *info,
+		union iwreq_data *uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	u32 u, oid = OID_INL_CONFIG;
+
+	down_write(&priv->mib_sem);
+	mgt_get(priv, OID_INL_CONFIG, &u);
+
+	if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0))
+		/* disable spy */
+		u &= ~INL_CONFIG_RXANNEX;
+	else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0))
+		/* enable spy */
+		u |= INL_CONFIG_RXANNEX;
+
+	mgt_set(priv, OID_INL_CONFIG, &u);
+	mgt_commit_list(priv, &oid, 1);
+	up_write(&priv->mib_sem);
+
+	return iw_handler_set_spy(ndev, info, uwrq, extra);
 }
 
 static const iw_handler prism54_handler[] = {
@@ -2094,7 +2048,7 @@
 	(iw_handler) NULL,	/* SIOCGIWPRIV */
 	(iw_handler) NULL,	/* SIOCSIWSTATS */
 	(iw_handler) NULL,	/* SIOCGIWSTATS */
-	iw_handler_set_spy,	/* SIOCSIWSPY */
+	prism54_set_spy,	/* SIOCSIWSPY */
 	iw_handler_get_spy,	/* SIOCGIWSPY */
 	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
 	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
@@ -2129,33 +2083,50 @@
 /* The low order bit identify a SET (0) or a GET (1) ioctl.  */
 
 #define PRISM54_RESET		SIOCIWFIRSTPRIV
-#define PRISM54_GET_BEACON	SIOCIWFIRSTPRIV+1
-#define PRISM54_SET_BEACON	SIOCIWFIRSTPRIV+2
-#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+3
-#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+4
-#define PRISM54_GET_MAC 	   SIOCIWFIRSTPRIV+5
-#define PRISM54_ADD_MAC 	   SIOCIWFIRSTPRIV+6
+#define PRISM54_GET_POLICY	SIOCIWFIRSTPRIV+1
+#define PRISM54_SET_POLICY	SIOCIWFIRSTPRIV+2
+#define PRISM54_GET_MAC		SIOCIWFIRSTPRIV+3
+#define PRISM54_ADD_MAC		SIOCIWFIRSTPRIV+4
+
+#define PRISM54_DEL_MAC		SIOCIWFIRSTPRIV+6
+
+#define PRISM54_KICK_MAC	SIOCIWFIRSTPRIV+8
 
-#define PRISM54_DEL_MAC    SIOCIWFIRSTPRIV+8
+#define PRISM54_KICK_ALL	SIOCIWFIRSTPRIV+10
 
-#define PRISM54_KICK_MAC   SIOCIWFIRSTPRIV+10
+#define PRISM54_GET_WPA		SIOCIWFIRSTPRIV+11
+#define PRISM54_SET_WPA		SIOCIWFIRSTPRIV+12
 
-#define PRISM54_KICK_ALL   SIOCIWFIRSTPRIV+12
+#define PRISM54_DBG_OID		SIOCIWFIRSTPRIV+14
+#define PRISM54_DBG_GET_OID	SIOCIWFIRSTPRIV+15
+#define PRISM54_DBG_SET_OID	SIOCIWFIRSTPRIV+16
 
-#define PRISM54_GET_WPA	   SIOCIWFIRSTPRIV+13
-#define PRISM54_SET_WPA	   SIOCIWFIRSTPRIV+14
+#define PRISM54_GET_OID		SIOCIWFIRSTPRIV+17
+#define PRISM54_SET_OID_U32	SIOCIWFIRSTPRIV+18
+#define	PRISM54_SET_OID_STR	SIOCIWFIRSTPRIV+20
+#define	PRISM54_SET_OID_ADDR	SIOCIWFIRSTPRIV+22
 
-#define PRISM54_OID	   SIOCIWFIRSTPRIV+16
-#define PRISM54_GET_OID	   SIOCIWFIRSTPRIV+17
-#define PRISM54_SET_OID	   SIOCIWFIRSTPRIV+18
+#define PRISM54_GET_PRISMHDR	SIOCIWFIRSTPRIV+23
+#define PRISM54_SET_PRISMHDR	SIOCIWFIRSTPRIV+24
+
+#define IWPRIV_SET_U32(n,x)	{ n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_SET_SSID(n,x)	{ n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_SET_ADDR(n,x)	{ n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_GET(n,x)	{ n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x }
+
+#define IWPRIV_U32(n,x)		IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x)
+#define IWPRIV_SSID(n,x)	IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x)
+#define IWPRIV_ADDR(n,x)	IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x)
+
+/* Note : limited to 128 private ioctls (wireless tools 26) */
 
 static const struct iw_priv_args prism54_private_args[] = {
 /*{ cmd, set_args, get_args, name } */
 	{PRISM54_RESET, 0, 0, "reset"},
-	{PRISM54_GET_BEACON, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-	 "getBeaconPeriod"},
-	{PRISM54_SET_BEACON, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
-	 "setBeaconPeriod"},
+	{PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "get_prismhdr"},
+	{PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "set_prismhdr"},
 	{PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 	 "getPolicy"},
 	{PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
@@ -2172,15 +2143,77 @@
 	 "get_wpa"},
 	{PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
 	 "set_wpa"},
-	{PRISM54_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oid"},
-	{PRISM54_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "get_oid"},
-	{PRISM54_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "set_oid"},
+	{PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "dbg_oid"},
+	{PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"},
+	{PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"},
+	/* --- sub-ioctls handlers --- */
+	{PRISM54_GET_OID,
+	 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""},
+	{PRISM54_SET_OID_U32,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""},
+	{PRISM54_SET_OID_STR,
+	 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
+	{PRISM54_SET_OID_ADDR,
+	 IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
+	/* --- sub-ioctls definitions --- */
+	IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"),
+	IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"),
+	IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"),
+	IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"),
+	IWPRIV_U32(DOT11_OID_STATE, "state"),
+	IWPRIV_U32(DOT11_OID_AID, "aid"),
+
+	IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"),
+
+	IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"),
+	IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"),
+	IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"),
+
+	IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"),
+	IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"),
+	IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"),
+
+	IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"),
+
+	IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"),
+	IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"),
+	IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"),
+	IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"),
+	IWPRIV_U32(DOT11_OID_PSM, "psm"),
+
+	IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"),
+	IWPRIV_U32(DOT11_OID_CLIENTS, "clients"),
+	IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"),
+	IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"),
+	IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"),
+	IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"),
+	IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"),
+	IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"),
+	IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"),
+	IWPRIV_GET(DOT11_OID_RATES, "rates"),
+	IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"),
+	IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"),
+	IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"),
+
+	IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"),
+	IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"),
+	IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"),
+	IWPRIV_U32(DOT11_OID_PROFILES, "profile"),
+	IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"),
+	IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"),
+
+	IWPRIV_GET(DOT11_OID_BSSS, "bsss"),
+	IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"),
+	IWPRIV_U32(OID_INL_MODE, "mode"),
+	IWPRIV_U32(OID_INL_CONFIG, "config"),
+	IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"),
+	IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"),
+	IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"),
 };
 
 static const iw_handler prism54_private_handler[] = {
 	(iw_handler) prism54_reset,
-	(iw_handler) prism54_get_beacon,
-	(iw_handler) prism54_set_beacon,
 	(iw_handler) prism54_get_policy,
 	(iw_handler) prism54_set_policy,
 	(iw_handler) prism54_get_mac,
@@ -2194,9 +2227,17 @@
 	(iw_handler) prism54_get_wpa,
 	(iw_handler) prism54_set_wpa,
 	(iw_handler) NULL,
-	(iw_handler) prism54_oid,
+	(iw_handler) prism54_debug_oid,
+	(iw_handler) prism54_debug_get_oid,
+	(iw_handler) prism54_debug_set_oid,
 	(iw_handler) prism54_get_oid,
-	(iw_handler) prism54_set_oid,
+	(iw_handler) prism54_set_u32,
+	(iw_handler) NULL,
+	(iw_handler) prism54_set_raw,
+	(iw_handler) NULL,
+	(iw_handler) prism54_set_raw,
+	(iw_handler) prism54_get_prismhdr,
+	(iw_handler) prism54_set_prismhdr,
 };
 
 const struct iw_handler_def prism54_handler_def = {
@@ -2207,5 +2248,14 @@
 	.standard = (iw_handler *) prism54_handler,
 	.private = (iw_handler *) prism54_private_handler,
 	.private_args = (struct iw_priv_args *) prism54_private_args,
+	.spy_offset = offsetof(islpci_private, spy_data),
 };
 
+/* For ioctls that don't work with the new API */
+
+int
+prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+
+	return -EOPNOTSUPP;
+}
--- diff/drivers/net/wireless/prism54/isl_ioctl.h	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/isl_ioctl.h	2004-05-27 18:34:17.000000000 +0100
@@ -1,4 +1,4 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.h,v 1.30 2004/01/30 16:24:00 ajfa Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.h,v 1.32 2004/04/17 08:46:04 ajfa Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *            (C) 2003 Aurelien Alleaume <slts@free.fr>
@@ -30,7 +30,6 @@
 #define SUPPORTED_WIRELESS_EXT                  16
 
 void prism54_mib_init(islpci_private *);
-void prism54_mib_init_work(islpci_private *);
 
 struct iw_statistics *prism54_get_wireless_stats(struct net_device *);
 void prism54_update_stats(islpci_private *);
--- diff/drivers/net/wireless/prism54/isl_oid.h	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/isl_oid.h	2004-05-27 18:34:17.000000000 +0100
@@ -1,8 +1,9 @@
 /*
- *  $Id: isl_oid.h,v 1.3 2004/03/09 09:05:27 mcgrof Exp $
+ *  $Id: isl_oid.h,v 1.6 2004/03/19 20:54:33 ajfa Exp $
  *  
  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
  *  Copyright (C) 2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
  *
  *  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
@@ -457,16 +458,29 @@
 	OID_NUM_LAST
 };
 
-/* We  could add more flags. eg: in which mode are they allowed, ro, rw, ...*/
-#define OID_FLAG_CACHED	0x01
-#define OID_FLAG_U32	0x02
-#define OID_FLAG_MLMEEX	0x04	/* this type is special because of a variable
-				   size field when sending. Not yet implemented (not used in driver). */
+#define OID_FLAG_CACHED		0x80
+#define OID_FLAG_TYPE		0x7f
+
+#define OID_TYPE_U32		0x01
+#define OID_TYPE_SSID		0x02
+#define OID_TYPE_KEY		0x03
+#define OID_TYPE_BUFFER		0x04
+#define OID_TYPE_BSS		0x05
+#define OID_TYPE_BSSLIST	0x06
+#define OID_TYPE_FREQUENCIES	0x07
+#define OID_TYPE_MLME		0x08
+#define OID_TYPE_MLMEEX		0x09
+#define OID_TYPE_ADDR		0x0A
+#define OID_TYPE_RAW		0x0B
+
+/* OID_TYPE_MLMEEX is special because of a variable size field when sending.
+ * Not yet implemented (not used in driver anyway).
+ */
 
 struct oid_t {
 	enum oid_num_t oid;
 	short range;		/* to define a range of oid */
-	short size;		/* size of the associated data */
+	short size;		/* max size of the associated data */
 	char flags;
 };
 
@@ -478,6 +492,7 @@
 #define	IWMAX_BITRATES	20
 #define	IWMAX_BSS	24
 #define IWMAX_FREQ	30
+#define PRIV_STR_SIZE	1024
 
 #endif				/* !defined(_ISL_OID_H) */
 /* EOF */
--- diff/drivers/net/wireless/prism54/islpci_dev.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/islpci_dev.c	2004-05-27 18:34:17.000000000 +0100
@@ -1,4 +1,4 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.c,v 1.68 2004/02/28 03:06:07 mcgrof Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.c,v 1.78 2004/04/27 17:22:35 ajfa Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
@@ -30,6 +30,7 @@
 
 #include <asm/io.h>
 
+#include "prismcompat.h"
 #include "isl_38xx.h"
 #include "isl_ioctl.h"
 #include "islpci_dev.h"
@@ -37,12 +38,6 @@
 #include "islpci_eth.h"
 #include "oid_mgt.h"
 
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-#define prism54_synchronize_irq(irq) synchronize_irq()
-#else
-#define prism54_synchronize_irq(irq) synchronize_irq(irq)
-#endif
-
 #define ISL3877_IMAGE_FILE	"isl3877"
 #define ISL3890_IMAGE_FILE	"isl3890"
 
@@ -74,7 +69,9 @@
 	if (reg & ISL38XX_CTRL_STAT_SLEEPMODE)
 		/* device is in sleep mode, IRQ was generated by someone else */
 	{
-		printk(KERN_DEBUG "Assuming someone else called the IRQ\n");
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n");
+#endif
 		return IRQ_NONE;
 	}
 
@@ -325,11 +322,7 @@
 	printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name);
 
 	rc = isl38xx_upload_firmware(priv->firmware,
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,75))
-		&priv->pdev->dev,
-#else
-		pci_name(priv->pdev),
-#endif
+		PRISM_FW_PDEV,
 		priv->device_base,
 		priv->device_host_address);
 	if (rc) {
@@ -357,15 +350,8 @@
 	int result = -ETIME;
 	int count;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-	/* This is 2.6 specific, nicer, shorter, but not in 2.4 yet */
-	DEFINE_WAIT(wait);
-	prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE);
-#else
-	DECLARE_WAITQUEUE(wait, current);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	add_wait_queue(&priv->reset_done, &wait);
-#endif
+	PRISM_DEFWAITQ(wait);
+	PRISM_PREPWAITQ(priv->reset_done, wait);
 	
 	/* now the last step is to reset the interface */
 	isl38xx_interface_reset(priv->device_base, priv->device_host_address);
@@ -390,13 +376,7 @@
 
 	}
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-	/* 2.6 specific too */
-	finish_wait(&priv->reset_done, &wait);
-#else
-	remove_wait_queue(&priv->reset_done, &wait);
-	set_current_state(TASK_RUNNING);
-#endif
+	PRISM_ENDWAITQ(priv->reset_done, wait);
 
 	if(result)
 		return result;
@@ -410,7 +390,9 @@
 	 * the IRQ line until we know for sure the reset went through */
 	isl38xx_enable_common_interrupts(priv->device_base);
 
-	prism54_mib_init_work(priv);
+	down_write(&priv->mib_sem);
+	mgt_commit(priv);
+	up_write(&priv->mib_sem);
 
 	islpci_set_state(priv, PRV_STATE_READY);
 
@@ -448,9 +430,9 @@
 	/* reset the mgmt receive queue */
 	for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) {
 		isl38xx_fragment *frag = &cb->rx_data_mgmt[counter];
-		frag->size = MGMT_FRAME_SIZE;
+		frag->size = cpu_to_le16(MGMT_FRAME_SIZE);
 		frag->flags = 0;
-		frag->address = priv->mgmt_rx[counter].pci_addr;
+		frag->address = cpu_to_le32(priv->mgmt_rx[counter].pci_addr);
 	}
 
 	for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
@@ -580,6 +562,7 @@
 			skb = NULL;
 			goto out_free;
 		}
+		skb_reserve(skb, (4 - (long) skb->data) & 0x03);
 		/* add the new allocated sk_buff to the buffer array */
 		priv->data_low_rx[counter] = skb;
 
@@ -715,9 +698,9 @@
 	priv = netdev_priv(ndev);
 	priv->ndev = ndev;
 	priv->pdev = pdev;
-
+	priv->monitor_type = ARPHRD_IEEE80211;
 	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
-		ARPHRD_IEEE80211: ARPHRD_ETHER;
+		priv->monitor_type : ARPHRD_ETHER;
 
 	/* save the start and end address of the PCI memory area */
 	ndev->mem_start = (unsigned long) priv->device_base;
@@ -743,9 +726,11 @@
 	/* initialize workqueue's */
 	INIT_WORK(&priv->stats_work,
 		  (void (*)(void *)) prism54_update_stats, priv);
-
 	priv->stats_timestamp = 0;
 
+	INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv);
+	priv->reset_task_pending = 0;
+
 	/* allocate various memory areas */
 	if (islpci_alloc_memory(priv))
 		goto do_free_netdev;
--- diff/drivers/net/wireless/prism54/islpci_dev.h	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/islpci_dev.h	2004-05-27 18:34:17.000000000 +0100
@@ -1,8 +1,9 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.h,v 1.53 2004/02/28 03:06:07 mcgrof Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.h,v 1.59 2004/03/20 16:58:36 mcgrof Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc. 
  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
  *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *  Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -25,22 +26,9 @@
 #include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
+#include <net/iw_handler.h>
 #include <linux/list.h>
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
-# include <linux/workqueue.h>
-#else
-# include <linux/tqueue.h>
-# define work_struct tq_struct
-# define INIT_WORK INIT_TQUEUE
-# define schedule_work schedule_task
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
-#define free_netdev(x) kfree(x) 
-#define pci_name(x) x->slot_name 
-#endif
-
 #include "isl_38xx.h"
 #include "isl_oid.h"
 #include "islpci_mgt.h"
@@ -110,6 +98,10 @@
 	struct iw_statistics local_iwstatistics;
 	struct iw_statistics iwstatistics;
 
+	struct iw_spy_data spy_data; /* iwspy support */
+
+	int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
+
 	struct islpci_acl acl;
 
 	/* PCI bus allocation & configuration members */
@@ -181,12 +173,15 @@
 	islpci_state_t state;
 	int state_off;		/* enumeration of off-state, if 0 then
 				 * we're not in any off-state */
-	
+
 	/* WPA stuff */
 	int wpa; /* WPA mode enabled */
 	struct list_head bss_wpa_list;
 	int num_bss_wpa;
 	struct semaphore wpa_sem;
+
+	struct work_struct reset_task;
+	int reset_task_pending;
 } islpci_private;
 
 static inline islpci_state_t
@@ -201,12 +196,6 @@
 
 #define ISLPCI_TX_TIMEOUT               (2*HZ)
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,75))
-# define irqreturn_t void
-# define IRQ_HANDLED
-# define IRQ_NONE
-#endif
-
 irqreturn_t islpci_interrupt(int, void *, struct pt_regs *);
 
 int prism54_post_setup(islpci_private *, int);
--- diff/drivers/net/wireless/prism54/islpci_eth.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/islpci_eth.c	2004-05-27 18:34:17.000000000 +0100
@@ -1,7 +1,7 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.c,v 1.27 2004/01/30 16:24:00 ajfa Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.c,v 1.37 2004/05/20 06:24:12 ajfa Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
- *
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
  *  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
@@ -24,10 +24,13 @@
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/if_arp.h>
 
+#include "prismcompat.h"
 #include "isl_38xx.h"
 #include "islpci_eth.h"
 #include "islpci_mgt.h"
+#include "oid_mgt.h"
 
 /******************************************************************************
     Network Interface functions
@@ -102,7 +105,7 @@
 
 	/* check whether the destination queue has enough fragments for the frame */
 	curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]);
-	if (curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE) {
+	if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) {
 		printk(KERN_ERR "%s: transmit device queue full when awake\n",
 		       ndev->name);
 		netif_stop_queue(ndev);
@@ -118,7 +121,7 @@
 	/* Check alignment and WDS frame formatting. The start of the packet should
 	 * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes
 	 * and add WDS address information */
-	if (((long) skb->data & 0x03) | init_wds) {
+	if (unlikely(((long) skb->data & 0x03) | init_wds)) {
 		/* get the number of bytes to add and re-allign */
 		offset = (4 - (long) skb->data) & 0x03;
 		offset += init_wds ? 6 : 0;
@@ -189,7 +192,7 @@
 	pci_map_address = pci_map_single(priv->pdev,
 					 (void *) skb->data, skb->len,
 					 PCI_DMA_TODEVICE);
-	if (pci_map_address == 0) {
+	if (unlikely(pci_map_address == 0)) {
 		printk(KERN_WARNING "%s: cannot map buffer to PCI\n",
 		       ndev->name);
 
@@ -205,7 +208,7 @@
 	priv->data_low_tx[index] = skb;
 	/* set the proper fragment start address and size information */
 	fragment->size = cpu_to_le16(frame_size);
-	fragment->flags = cpu_to_le16(0);  /* set to 1 if more fragments */
+	fragment->flags = cpu_to_le16(0);	/* set to 1 if more fragments */
 	fragment->address = cpu_to_le32(pci_map_address);
 	curr_frag++;
 
@@ -215,7 +218,7 @@
 	cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag);
 
 	if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD
-	                                           > ISL38XX_CB_TX_QSIZE) {
+	    > ISL38XX_CB_TX_QSIZE) {
 		/* stop sends from upper layers */
 		netif_stop_queue(ndev);
 
@@ -236,7 +239,7 @@
 
 	return 0;
 
- drop_free:
+      drop_free:
 	/* free the skbuf structure before aborting */
 	dev_kfree_skb(skb);
 	skb = NULL;
@@ -246,6 +249,69 @@
 	return err;
 }
 
+static inline int
+islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb)
+{
+	/* The card reports full 802.11 packets but with a 20 bytes
+	 * header and without the FCS. But there a is a bit that
+	 * indicates if the packet is corrupted :-) */
+	struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data;
+	if (hdr->flags & 0x01)
+		/* This one is bad. Drop it ! */
+		return -1;
+	if (priv->ndev->type == ARPHRD_IEEE80211_PRISM) {
+		struct avs_80211_1_header *avs;
+		/* extract the relevant data from the header */
+		u32 clock = le32_to_cpu(hdr->clock);
+		u8 rate = hdr->rate;
+		u16 freq = le16_to_cpu(hdr->freq);
+		u8 rssi = hdr->rssi;
+
+		skb_pull(*skb, sizeof (struct rfmon_header));
+
+		if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) {
+			struct sk_buff *newskb = skb_copy_expand(*skb,
+								 sizeof (struct
+									 avs_80211_1_header),
+								 0, GFP_ATOMIC);
+			if (newskb) {
+				dev_kfree_skb_irq(*skb);
+				*skb = newskb;
+			} else
+				return -1;
+			/* This behavior is not very subtile... */
+		}
+
+		/* make room for the new header and fill it. */
+		avs =
+		    (struct avs_80211_1_header *) skb_push(*skb,
+							   sizeof (struct
+								   avs_80211_1_header));
+
+		avs->version = cpu_to_be32(P80211CAPTURE_VERSION);
+		avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header));
+		avs->mactime = cpu_to_be64(le64_to_cpu(clock));
+		avs->hosttime = cpu_to_be64(jiffies);
+		avs->phytype = cpu_to_be32(6);	/*OFDM: 6 for (g), 8 for (a) */
+		avs->channel = cpu_to_be32(channel_of_freq(freq));
+		avs->datarate = cpu_to_be32(rate * 5);
+		avs->antenna = cpu_to_be32(0);	/*unknown */
+		avs->priority = cpu_to_be32(0);	/*unknown */
+		avs->ssi_type = cpu_to_be32(3);	/*2: dBm, 3: raw RSSI */
+		avs->ssi_signal = cpu_to_be32(rssi & 0x7f);
+		avs->ssi_noise = cpu_to_be32(priv->local_iwstatistics.qual.noise);	/*better than 'undefined', I assume */
+		avs->preamble = cpu_to_be32(0);	/*unknown */
+		avs->encoding = cpu_to_be32(0);	/*unknown */
+	} else
+		skb_pull(*skb, sizeof (struct rfmon_header));
+
+	(*skb)->protocol = htons(ETH_P_802_2);
+	(*skb)->mac.raw = (*skb)->data;
+	(*skb)->pkt_type = PACKET_OTHERHOST;
+
+	return 0;
+}
+
 int
 islpci_eth_receive(islpci_private *priv)
 {
@@ -266,7 +332,8 @@
 	index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE;
 	size = le16_to_cpu(control_block->rx_data_low[index].size);
 	skb = priv->data_low_rx[index];
-	offset = ((unsigned long) le32_to_cpu(control_block->rx_data_low[index].address) -
+	offset = ((unsigned long)
+		  le32_to_cpu(control_block->rx_data_low[index].address) -
 		  (unsigned long) skb->data) & 3;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
@@ -314,29 +381,32 @@
 	/* do some additional sk_buff and network layer parameters */
 	skb->dev = ndev;
 
-	/* take care of monitor mode */
-	if (priv->iw_mode == IW_MODE_MONITOR) {
-		/* The card reports full 802.11 packets but with a 20 bytes
-		 * header and without the FCS. But there a is a bit that
-		 * indicates if the packet is corrupted :-) */
-		/* int i; */
-		if (skb->data[8] & 0x01){
-			/* This one is bad. Drop it !*/
-			discard = 1;
-			/* printk("BAD\n");*/
+	/* take care of monitor mode and spy monitoring. */
+	if (unlikely(priv->iw_mode == IW_MODE_MONITOR))
+		discard = islpci_monitor_rx(priv, &skb);
+	else {
+		if (unlikely(skb->data[2 * ETH_ALEN] == 0)) {
+			/* The packet has a rx_annex. Read it for spy monitoring, Then
+			 * remove it, while keeping the 2 leading MAC addr.
+			 */
+			struct iw_quality wstats;
+			struct rx_annex_header *annex =
+			    (struct rx_annex_header *) skb->data;
+			wstats.level = annex->rfmon.rssi;
+			/* The noise value can be a bit outdated if nobody's
+			 * reading wireless stats... */
+			wstats.noise = priv->local_iwstatistics.qual.noise;
+			wstats.qual = wstats.level - wstats.noise;
+			wstats.updated = 0x07;
+			/* Update spy records */
+			wireless_spy_update(ndev, annex->addr2, &wstats);
+
+			memcpy(skb->data + sizeof (struct rfmon_header),
+			       skb->data, 2 * ETH_ALEN);
+			skb_pull(skb, sizeof (struct rfmon_header));
 		}
-		/*
-		for(i=0;i<50;i++)
-			printk("%2.2X:",skb->data[i]);
-		printk("\n");
-		*/		
-		skb_pull(skb, 20);
-		skb->protocol = htons(ETH_P_802_2);
-		skb->mac.raw = skb->data;
-		skb->pkt_type = PACKET_OTHERHOST;
-	} else
 		skb->protocol = eth_type_trans(skb, ndev);
-
+	}
 	skb->ip_summed = CHECKSUM_NONE;
 	priv->statistics.rx_packets++;
 	priv->statistics.rx_bytes += size;
@@ -348,11 +418,10 @@
 	     skb->data[0], skb->data[1], skb->data[2], skb->data[3],
 	     skb->data[4], skb->data[5]);
 #endif
-	if (discard) {
-		dev_kfree_skb(skb);
+	if (unlikely(discard)) {
+		dev_kfree_skb_irq(skb);
 		skb = NULL;
-	}
-	else
+	} else
 		netif_rx(skb);
 
 	/* increment the read index for the rx data low queue */
@@ -365,11 +434,13 @@
 	       index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) {
 		/* allocate an sk_buff for received data frames storage
 		 * include any required allignment operations */
-		if (skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2), skb == NULL) {
+		skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2);
+		if (unlikely(skb == NULL)) {
 			/* error allocating an sk_buff structure elements */
 			DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n");
 			break;
 		}
+		skb_reserve(skb, (4 - (long) skb->data) & 0x03);
 		/* store the new skb structure pointer */
 		index = index % ISL38XX_CB_RX_QSIZE;
 		priv->data_low_rx[index] = skb;
@@ -385,13 +456,13 @@
 		    pci_map_single(priv->pdev, (void *) skb->data,
 				   MAX_FRAGMENT_SIZE_RX + 2,
 				   PCI_DMA_FROMDEVICE);
-		if (priv->pci_map_rx_address[index] == (dma_addr_t) NULL) {
+		if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) {
 			/* error mapping the buffer to device accessable memory address */
 			DEBUG(SHOW_ERROR_MESSAGES,
 			      "Error mapping DMA address\n");
 
 			/* free the skbuf structure before aborting */
-			dev_kfree_skb((struct sk_buff *) skb);
+			dev_kfree_skb_irq((struct sk_buff *) skb);
 			skb = NULL;
 			break;
 		}
@@ -403,7 +474,7 @@
 		wmb();
 
 		/* increment the driver read pointer */
-		add_le32p((u32 *) & control_block->
+		add_le32p((u32 *) &control_block->
 			  driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1);
 	}
 
@@ -414,6 +485,15 @@
 }
 
 void
+islpci_do_reset_and_wake(void *data)
+{
+	islpci_private *priv = (islpci_private *) data;
+	islpci_reset(priv, 1);
+	netif_wake_queue(priv->ndev);
+	priv->reset_task_pending = 0;
+}
+
+void
 islpci_eth_tx_timeout(struct net_device *ndev)
 {
 	islpci_private *priv = netdev_priv(ndev);
@@ -422,13 +502,11 @@
 	/* increment the transmit error counter */
 	statistics->tx_errors++;
 
-#if 0
-	/* don't do this here! we are not allowed to sleep since we are in interrupt context */
-	if (islpci_reset(priv))
-		printk(KERN_ERR "%s: error on TX timeout card reset!\n",
-		       ndev->name);
-#endif
+	if (!priv->reset_task_pending) {
+		priv->reset_task_pending = 1;
+		netif_stop_queue(ndev);
+		schedule_work(&priv->reset_task);
+	}
 
-	/* netif_wake_queue(ndev); */
 	return;
 }
--- diff/drivers/net/wireless/prism54/islpci_eth.h	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/islpci_eth.h	2004-05-27 18:34:17.000000000 +0100
@@ -1,4 +1,4 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.h,v 1.5 2004/01/12 22:16:32 jmaurer Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.h,v 1.7 2004/03/19 20:54:33 ajfa Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *
@@ -23,9 +23,51 @@
 #include "isl_38xx.h"
 #include "islpci_dev.h"
 
+struct rfmon_header {
+	u16 unk0;		/* = 0x0000 */
+	u16 length;		/* = 0x1400 */
+	u32 clock;		/* 1MHz clock */
+	u8 flags;
+	u8 unk1;
+	u8 rate;
+	u8 unk2;
+	u16 freq;
+	u16 unk3;
+	u8 rssi;
+	u8 padding[3];
+} __attribute__ ((packed));
+
+struct rx_annex_header {
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	struct rfmon_header rfmon;
+} __attribute__ ((packed));
+
+/* wlan-ng (and hopefully others) AVS header, version one.  Fields in
+ * network byte order. */
+#define P80211CAPTURE_VERSION 0x80211001
+
+struct avs_80211_1_header {
+	uint32_t version;
+	uint32_t length;
+	uint64_t mactime;
+	uint64_t hosttime;
+	uint32_t phytype;
+	uint32_t channel;
+	uint32_t datarate;
+	uint32_t antenna;
+	uint32_t priority;
+	uint32_t ssi_type;
+	int32_t ssi_signal;
+	int32_t ssi_noise;
+	uint32_t preamble;
+	uint32_t encoding;
+};
+
 void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *);
 int islpci_eth_transmit(struct sk_buff *, struct net_device *);
 int islpci_eth_receive(islpci_private *);
 void islpci_eth_tx_timeout(struct net_device *);
+void islpci_do_reset_and_wake(void *data);
 
 #endif				/* _ISL_GEN_H */
--- diff/drivers/net/wireless/prism54/islpci_hotplug.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/islpci_hotplug.c	2004-05-27 18:34:17.000000000 +0100
@@ -1,4 +1,4 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_hotplug.c,v 1.56 2004/02/26 23:33:02 mcgrof Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_hotplug.c,v 1.60 2004/05/13 13:19:47 msw Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
@@ -24,12 +24,13 @@
 #include <linux/delay.h>
 #include <linux/init.h> /* For __init, __exit */
 
+#include "prismcompat.h"
 #include "islpci_dev.h"
 #include "islpci_mgt.h"		/* for pc_debug */
 #include "isl_oid.h"
 
 #define DRV_NAME	"prism54"
-#define DRV_VERSION	"1.1"
+#define DRV_VERSION	"1.2"
 
 MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
 MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
--- diff/drivers/net/wireless/prism54/islpci_mgt.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/islpci_mgt.c	2004-05-27 18:34:17.000000000 +0100
@@ -1,4 +1,4 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.c,v 1.40 2004/02/01 10:57:23 mcgrof Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.c,v 1.46 2004/04/19 18:33:45 ajfa Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright 2004 Jens Maurer <Jens.Maurer@gmx.net>
@@ -22,12 +22,12 @@
 #include <linux/netdevice.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/moduleparam.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 #include <linux/if_arp.h>
 
+#include "prismcompat.h"
 #include "isl_38xx.h"
 #include "islpci_mgt.h"
 #include "isl_oid.h"		/* additional types and defs for isl38xx fw */
@@ -63,7 +63,6 @@
     Queue handling for management frames
 ******************************************************************************/
 
-  
 /*
  * Helper function to create a PIMFOR management frame header.
  */
@@ -86,8 +85,8 @@
 {
 	pimfor_header_t *h = data;
 
-        while ((void *) h < data + len) {
-		if(h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) {
+	while ((void *) h < data + len) {
+		if (h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) {
 			le32_to_cpus(&h->oid);
 			le32_to_cpus(&h->length);
 		} else {
@@ -108,8 +107,8 @@
 islpci_mgmt_rx_fill(struct net_device *ndev)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	isl38xx_control_block *cb =    /* volatile not needed */
-		(isl38xx_control_block *) priv->control_block;
+	isl38xx_control_block *cb =	/* volatile not needed */
+	    (isl38xx_control_block *) priv->control_block;
 	u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
@@ -124,7 +123,8 @@
 		if (buf->mem == NULL) {
 			buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC);
 			if (!buf->mem) {
-				printk(KERN_WARNING "Error allocating management frame.\n");
+				printk(KERN_WARNING
+				       "Error allocating management frame.\n");
 				return -ENOMEM;
 			}
 			buf->size = MGMT_FRAME_SIZE;
@@ -133,24 +133,24 @@
 			buf->pci_addr = pci_map_single(priv->pdev, buf->mem,
 						       MGMT_FRAME_SIZE,
 						       PCI_DMA_FROMDEVICE);
-			if(!buf->pci_addr) {
-				printk(KERN_WARNING "Failed to make memory DMA'able\n.");
+			if (!buf->pci_addr) {
+				printk(KERN_WARNING
+				       "Failed to make memory DMA'able\n.");
 				return -ENOMEM;
 			}
 		}
 
-                /* be safe: always reset control block information */
+		/* be safe: always reset control block information */
 		frag->size = cpu_to_le16(MGMT_FRAME_SIZE);
 		frag->flags = 0;
 		frag->address = cpu_to_le32(buf->pci_addr);
 		curr++;
 
-                /* The fragment address in the control block must have
-                 * been written before announcing the frame buffer to
-                 * device */
+		/* The fragment address in the control block must have
+		 * been written before announcing the frame buffer to
+		 * device */
 		wmb();
-		cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] =
-			cpu_to_le32(curr);
+		cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(curr);
 	}
 	return 0;
 }
@@ -168,7 +168,7 @@
 {
 	islpci_private *priv = netdev_priv(ndev);
 	isl38xx_control_block *cb =
-		(isl38xx_control_block *) priv->control_block;
+	    (isl38xx_control_block *) priv->control_block;
 	void *p;
 	int err = -EINVAL;
 	unsigned long flags;
@@ -242,25 +242,25 @@
 	priv->mgmt_tx[index] = buf;
 	frag = &cb->tx_data_mgmt[index];
 	frag->size = cpu_to_le16(frag_len);
-	frag->flags = 0;   /* for any other than the last fragment, set to 1 */
+	frag->flags = 0;	/* for any other than the last fragment, set to 1 */
 	frag->address = cpu_to_le32(buf.pci_addr);
 
 	/* The fragment address in the control block must have
 	 * been written before announcing the frame buffer to
 	 * device */
 	wmb();
-	cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag+1);
+	cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1);
 	spin_unlock_irqrestore(&priv->slock, flags);
 
 	/* trigger the device */
 	islpci_trigger(priv);
 	return 0;
 
- error_unlock:
+      error_unlock:
 	spin_unlock_irqrestore(&priv->slock, flags);
- error_free:
+      error_free:
 	kfree(buf.mem);
- error:
+      error:
 	return err;
 }
 
@@ -274,50 +274,49 @@
 {
 	islpci_private *priv = netdev_priv(ndev);
 	isl38xx_control_block *cb =
-		(isl38xx_control_block *) priv->control_block;
+	    (isl38xx_control_block *) priv->control_block;
 	u32 curr_frag;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
 	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n");
 #endif
 
-
-        /* Only once per interrupt, determine fragment range to
-         * process.  This avoids an endless loop (i.e. lockup) if
-         * frames come in faster than we can process them. */
+	/* Only once per interrupt, determine fragment range to
+	 * process.  This avoids an endless loop (i.e. lockup) if
+	 * frames come in faster than we can process them. */
 	curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]);
 	barrier();
 
-	for ( ; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) {
+	for (; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) {
 		pimfor_header_t *header;
 		u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE;
 		struct islpci_membuf *buf = &priv->mgmt_rx[index];
 		u16 frag_len;
 		int size;
 		struct islpci_mgmtframe *frame;
-              
-                /* I have no idea (and no documentation) if flags != 0
-                 * is possible.  Drop the frame, reuse the buffer. */
-                if(le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) {
-                        printk(KERN_WARNING "%s: unknown flags 0x%04x\n",
-                               ndev->name,
-                               le16_to_cpu(cb->rx_data_mgmt[index].flags));
-                        continue;
-                }
+
+		/* I have no idea (and no documentation) if flags != 0
+		 * is possible.  Drop the frame, reuse the buffer. */
+		if (le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) {
+			printk(KERN_WARNING "%s: unknown flags 0x%04x\n",
+			       ndev->name,
+			       le16_to_cpu(cb->rx_data_mgmt[index].flags));
+			continue;
+		}
 
 		/* The device only returns the size of the header(s) here. */
 		frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size);
 
 		/*
-                 * We appear to have no way to tell the device the
-                 * size of a receive buffer.  Thus, if this check
-                 * triggers, we likely have kernel heap corruption. */
-                if (frag_len > MGMT_FRAME_SIZE) {
-                        printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\
-n",
-                               ndev->name, frag_len, frag_len);
-                        frag_len = MGMT_FRAME_SIZE;
-                }
+		 * We appear to have no way to tell the device the
+		 * size of a receive buffer.  Thus, if this check
+		 * triggers, we likely have kernel heap corruption. */
+		if (frag_len > MGMT_FRAME_SIZE) {
+			printk(KERN_WARNING
+				"%s: Bogus packet size of %d (%#x).\n",
+				ndev->name, frag_len, frag_len);
+			frag_len = MGMT_FRAME_SIZE;
+		}
 
 		/* Ensure the results of device DMA are visible to the CPU. */
 		pci_dma_sync_single(priv->pdev, buf->pci_addr,
@@ -339,30 +338,32 @@
 #if VERBOSE > SHOW_ERROR_MESSAGES
 		DEBUG(SHOW_PIMFOR_FRAMES,
 		      "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n",
-		      header->operation, header->oid, header->device_id, 
+		      header->operation, header->oid, header->device_id,
 		      header->flags, header->length);
 
 		/* display the buffer contents for debugging */
 		display_buffer((char *) header, PIMFOR_HEADER_SIZE);
-		display_buffer((char *) header + PIMFOR_HEADER_SIZE, header->length);
+		display_buffer((char *) header + PIMFOR_HEADER_SIZE,
+			       header->length);
 #endif
 
 		/* nobody sends these */
 		if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) {
-			printk(KERN_DEBUG "%s: errant PIMFOR application frame\n",
+			printk(KERN_DEBUG
+			       "%s: errant PIMFOR application frame\n",
 			       ndev->name);
 			continue;
 		}
 
 		/* Determine frame size, skipping OID_INL_TUNNEL headers. */
 		size = PIMFOR_HEADER_SIZE + header->length;
-		frame = kmalloc(sizeof(struct islpci_mgmtframe) + size,
+		frame = kmalloc(sizeof (struct islpci_mgmtframe) + size,
 				GFP_ATOMIC);
 		if (!frame) {
-			printk(KERN_WARNING "%s: Out of memory, cannot handle oid 0x%08x\n",
-
+			printk(KERN_WARNING
+			       "%s: Out of memory, cannot handle oid 0x%08x\n",
 			       ndev->name, header->oid);
-			continue;        
+			continue;
 		}
 		frame->ndev = ndev;
 		memcpy(&frame->buf, header, size);
@@ -382,7 +383,7 @@
 			       header->oid, header->device_id, header->flags,
 			       header->length);
 #endif
-                      
+
 			/* Create work to handle trap out of interrupt
 			 * context. */
 			INIT_WORK(&frame->ws, prism54_process_trap, frame);
@@ -392,14 +393,13 @@
 			/* Signal the one waiting process that a response
 			 * has been received. */
 			if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) {
-				printk(KERN_WARNING "%s: mgmt response not collected\n",
+				printk(KERN_WARNING
+				       "%s: mgmt response not collected\n",
 				       ndev->name);
 				kfree(frame);
 			}
-                              
 #if VERBOSE > SHOW_ERROR_MESSAGES
-			DEBUG(SHOW_TRACING,
-			      "Wake up Mgmt Queue\n");
+			DEBUG(SHOW_TRACING, "Wake up Mgmt Queue\n");
 #endif
 			wake_up(&priv->mgmt_wqueue);
 		}
@@ -416,22 +416,22 @@
 islpci_mgt_cleanup_transmit(struct net_device *ndev)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	isl38xx_control_block *cb =    /* volatile not needed */
-		(isl38xx_control_block *) priv->control_block;
+	isl38xx_control_block *cb =	/* volatile not needed */
+	    (isl38xx_control_block *) priv->control_block;
 	u32 curr_frag;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-        DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n");
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n");
 #endif
 
 	/* Only once per cleanup, determine fragment range to
 	 * process.  This avoids an endless loop (i.e. lockup) if
 	 * the device became confused, incrementing device_curr_frag
 	 * rapidly. */
-	curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]); 
+	curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]);
 	barrier();
 
-	for ( ; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) {
+	for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) {
 		int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE;
 		struct islpci_membuf *buf = &priv->mgmt_tx[index];
 		pci_unmap_single(priv->pdev, buf->pci_addr, buf->size,
@@ -456,23 +456,14 @@
 	const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000;
 	long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies;
 	int err;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-	DEFINE_WAIT(wait);
-#else
-	DECLARE_WAITQUEUE(wait, current);
-#endif
+	PRISM_DEFWAITQ(wait);
 
 	if (down_interruptible(&priv->mgmt_sem))
 		return -ERESTARTSYS;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-	prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE);
-#else
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	add_wait_queue(&priv->mgmt_wqueue, &wait);
-#endif
+	PRISM_PREPWAITQ(priv->mgmt_wqueue, wait);
 	err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen);
-	if(err)
+	if (err)
 		goto out;
 
 	err = -ETIMEDOUT;
@@ -483,13 +474,24 @@
 		timeleft = schedule_timeout(wait_cycle_jiffies);
 		frame = xchg(&priv->mgmt_received, NULL);
 		if (frame) {
-			*recvframe = frame;
-			err = 0;
-			goto out;
-		}
-		if(timeleft == 0) {
-			printk(KERN_DEBUG "%s: timeout waiting for mgmt response %lu, trigging device\n",
-			       ndev->name, timeout_left);
+			if (frame->header->oid == oid) {
+				*recvframe = frame;
+				err = 0;
+				goto out;
+			} else {
+				printk(KERN_DEBUG
+				       "%s: expecting oid 0x%x, received 0x%x.\n",
+				       ndev->name, (unsigned int) oid,
+				       frame->header->oid);
+				kfree(frame);
+				frame = NULL;
+			}
+		}
+		if (timeleft == 0) {
+			printk(KERN_DEBUG
+				"%s: timeout waiting for mgmt response %lu, "
+				"triggering device\n",
+				ndev->name, timeout_left);
 			islpci_trigger(priv);
 		}
 		timeout_left += timeleft - wait_cycle_jiffies;
@@ -497,15 +499,9 @@
 	printk(KERN_WARNING "%s: timeout waiting for mgmt response\n",
 	       ndev->name);
 
-	/* TODO: we should reset the device here */     
- out:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-	finish_wait(&priv->mgmt_wqueue, &wait);
-#else
-	remove_wait_queue(&priv->mgmt_wqueue, &wait);
-	set_current_state(TASK_RUNNING);
-#endif
+	/* TODO: we should reset the device here */
+      out:
+	PRISM_ENDWAITQ(priv->mgmt_wqueue, wait);
 	up(&priv->mgmt_sem);
 	return err;
 }
-
--- diff/drivers/net/wireless/prism54/islpci_mgt.h	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/islpci_mgt.h	2004-05-27 18:34:17.000000000 +0100
@@ -1,4 +1,4 @@
-/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.h,v 1.22 2004/01/30 16:24:00 ajfa Exp $
+/*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.h,v 1.26 2004/04/26 10:09:58 msw Exp $
  *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
@@ -24,15 +24,6 @@
 #include <linux/wireless.h>
 #include <linux/skbuff.h>
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
-# include <linux/workqueue.h>
-#else
-# include <linux/tqueue.h>
-# define work_struct tq_struct
-# define INIT_WORK INIT_TQUEUE
-# define schedule_work schedule_task
-#endif
-
 /*
  *  Function definitions
  */
@@ -43,7 +34,7 @@
 #define TRACE(devname)   K_DEBUG(SHOW_TRACING, VERBOSE, "%s:  -> " __FUNCTION__ "()\n", devname)
 
 extern int pc_debug;
-static const int init_wds = 0;	/* help compiler optimize away dead code */
+#define init_wds   0	/* help compiler optimize away dead code */
 
 
 /* General driver definitions */
--- diff/drivers/net/wireless/prism54/oid_mgt.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/oid_mgt.c	2004-05-27 18:34:17.000000000 +0100
@@ -1,5 +1,5 @@
 /*   
- *  Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *  Copyright (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
  *
  *  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
@@ -16,6 +16,7 @@
  *
  */
 
+#include "prismcompat.h"
 #include "islpci_dev.h"
 #include "islpci_mgt.h"
 #include "isl_oid.h"
@@ -31,182 +32,206 @@
 	5240, 5260, 5280, 5300, 5320
 };
 
-#define OID_U32(x) {x, 0, sizeof(u32), OID_FLAG_U32}
-#define OID_U32_C(x) {x, 0, sizeof(u32), OID_FLAG_U32 | OID_FLAG_CACHED}
-#define OID_STRUCT(x,s) {x, 0, sizeof(s), 0}
-#define OID_STRUCT_C(x,s) {x, 0, sizeof(s), OID_FLAG_CACHED}
-#define OID_STRUCT_MLME(x){x, 0, sizeof(struct obj_mlme), 0}
-#define OID_STRUCT_MLMEEX(x){x, 0, sizeof(struct obj_mlmeex), OID_FLAG_MLMEEX}
+int
+channel_of_freq(int f)
+{
+	int c = 0;
+
+	if ((f >= 2412) && (f <= 2484)) {
+		while ((c < 14) && (f != frequency_list_bg[c]))
+			c++;
+		return (c >= 14) ? 0 : ++c;
+	} else if ((f >= (int) 5170) && (f <= (int) 5320)) {
+		while ((c < 12) && (f != frequency_list_a[c]))
+			c++;
+		return (c >= 12) ? 0 : (c + 37);
+	} else
+		return 0;
+}
+
+#define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t}
+#define OID_STRUCT_C(name,oid,s,t) OID_STRUCT(name,oid,s,t | OID_FLAG_CACHED)
+#define OID_U32(name,oid) OID_STRUCT(name,oid,u32,OID_TYPE_U32)
+#define OID_U32_C(name,oid) OID_STRUCT_C(name,oid,u32,OID_TYPE_U32)
+#define OID_STRUCT_MLME(name,oid) OID_STRUCT(name,oid,struct obj_mlme,OID_TYPE_MLME)
+#define OID_STRUCT_MLMEEX(name,oid) OID_STRUCT(name,oid,struct obj_mlmeex,OID_TYPE_MLMEEX)
 
-#define OID_UNKNOWN(x) {x, 0, 0, 0}
+#define OID_UNKNOWN(name,oid) OID_STRUCT(name,oid,0,0)
 
 struct oid_t isl_oid[] = {
-	[GEN_OID_MACADDRESS] = OID_STRUCT(0x00000000, u8[6]),
-	[GEN_OID_LINKSTATE] = OID_U32(0x00000001),
-	[GEN_OID_WATCHDOG] = OID_UNKNOWN(0x00000002),
-	[GEN_OID_MIBOP] = OID_UNKNOWN(0x00000003),
-	[GEN_OID_OPTIONS] = OID_UNKNOWN(0x00000004),
-	[GEN_OID_LEDCONFIG] = OID_UNKNOWN(0x00000005),
+	OID_STRUCT(GEN_OID_MACADDRESS, 0x00000000, u8[6], OID_TYPE_ADDR),
+	OID_U32(GEN_OID_LINKSTATE, 0x00000001),
+	OID_UNKNOWN(GEN_OID_WATCHDOG, 0x00000002),
+	OID_UNKNOWN(GEN_OID_MIBOP, 0x00000003),
+	OID_UNKNOWN(GEN_OID_OPTIONS, 0x00000004),
+	OID_UNKNOWN(GEN_OID_LEDCONFIG, 0x00000005),
 
 	/* 802.11 */
-	[DOT11_OID_BSSTYPE] = OID_U32_C(0x10000000),
-	[DOT11_OID_BSSID] = OID_STRUCT_C(0x10000001, u8[6]),
-	[DOT11_OID_SSID] = OID_STRUCT_C(0x10000002, struct obj_ssid),
-	[DOT11_OID_STATE] = OID_U32(0x10000003),
-	[DOT11_OID_AID] = OID_U32(0x10000004),
-	[DOT11_OID_COUNTRYSTRING] = OID_STRUCT(0x10000005, u8[4]),
-	[DOT11_OID_SSIDOVERRIDE] = OID_STRUCT_C(0x10000006, struct obj_ssid),
-
-	[DOT11_OID_MEDIUMLIMIT] = OID_U32(0x11000000),
-	[DOT11_OID_BEACONPERIOD] = OID_U32_C(0x11000001),
-	[DOT11_OID_DTIMPERIOD] = OID_U32(0x11000002),
-	[DOT11_OID_ATIMWINDOW] = OID_U32(0x11000003),
-	[DOT11_OID_LISTENINTERVAL] = OID_U32(0x11000004),
-	[DOT11_OID_CFPPERIOD] = OID_U32(0x11000005),
-	[DOT11_OID_CFPDURATION] = OID_U32(0x11000006),
-
-	[DOT11_OID_AUTHENABLE] = OID_U32_C(0x12000000),
-	[DOT11_OID_PRIVACYINVOKED] = OID_U32_C(0x12000001),
-	[DOT11_OID_EXUNENCRYPTED] = OID_U32_C(0x12000002),
-	[DOT11_OID_DEFKEYID] = OID_U32_C(0x12000003),
-	[DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key), OID_FLAG_CACHED},	/* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */
-	[DOT11_OID_STAKEY] = OID_UNKNOWN(0x12000008),
-	[DOT11_OID_REKEYTHRESHOLD] = OID_U32(0x12000009),
-	[DOT11_OID_STASC] = OID_UNKNOWN(0x1200000a),
-
-	[DOT11_OID_PRIVTXREJECTED] = OID_U32(0x1a000000),
-	[DOT11_OID_PRIVRXPLAIN] = OID_U32(0x1a000001),
-	[DOT11_OID_PRIVRXFAILED] = OID_U32(0x1a000002),
-	[DOT11_OID_PRIVRXNOKEY] = OID_U32(0x1a000003),
-
-	[DOT11_OID_RTSTHRESH] = OID_U32_C(0x13000000),
-	[DOT11_OID_FRAGTHRESH] = OID_U32_C(0x13000001),
-	[DOT11_OID_SHORTRETRIES] = OID_U32_C(0x13000002),
-	[DOT11_OID_LONGRETRIES] = OID_U32_C(0x13000003),
-	[DOT11_OID_MAXTXLIFETIME] = OID_U32_C(0x13000004),
-	[DOT11_OID_MAXRXLIFETIME] = OID_U32(0x13000005),
-	[DOT11_OID_AUTHRESPTIMEOUT] = OID_U32(0x13000006),
-	[DOT11_OID_ASSOCRESPTIMEOUT] = OID_U32(0x13000007),
-
-	[DOT11_OID_ALOFT_TABLE] = OID_UNKNOWN(0x1d000000),
-	[DOT11_OID_ALOFT_CTRL_TABLE] = OID_UNKNOWN(0x1d000001),
-	[DOT11_OID_ALOFT_RETREAT] = OID_UNKNOWN(0x1d000002),
-	[DOT11_OID_ALOFT_PROGRESS] = OID_UNKNOWN(0x1d000003),
-	[DOT11_OID_ALOFT_FIXEDRATE] = OID_U32(0x1d000004),
-	[DOT11_OID_ALOFT_RSSIGRAPH] = OID_UNKNOWN(0x1d000005),
-	[DOT11_OID_ALOFT_CONFIG] = OID_UNKNOWN(0x1d000006),
+	OID_U32_C(DOT11_OID_BSSTYPE, 0x10000000),
+	OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_SSID),
+	OID_STRUCT_C(DOT11_OID_SSID, 0x10000002, struct obj_ssid,
+		     OID_TYPE_SSID),
+	OID_U32(DOT11_OID_STATE, 0x10000003),
+	OID_U32(DOT11_OID_AID, 0x10000004),
+	OID_STRUCT(DOT11_OID_COUNTRYSTRING, 0x10000005, u8[4], OID_TYPE_RAW),
+	OID_STRUCT_C(DOT11_OID_SSIDOVERRIDE, 0x10000006, struct obj_ssid,
+		     OID_TYPE_SSID),
+
+	OID_U32(DOT11_OID_MEDIUMLIMIT, 0x11000000),
+	OID_U32_C(DOT11_OID_BEACONPERIOD, 0x11000001),
+	OID_U32(DOT11_OID_DTIMPERIOD, 0x11000002),
+	OID_U32(DOT11_OID_ATIMWINDOW, 0x11000003),
+	OID_U32(DOT11_OID_LISTENINTERVAL, 0x11000004),
+	OID_U32(DOT11_OID_CFPPERIOD, 0x11000005),
+	OID_U32(DOT11_OID_CFPDURATION, 0x11000006),
+
+	OID_U32_C(DOT11_OID_AUTHENABLE, 0x12000000),
+	OID_U32_C(DOT11_OID_PRIVACYINVOKED, 0x12000001),
+	OID_U32_C(DOT11_OID_EXUNENCRYPTED, 0x12000002),
+	OID_U32_C(DOT11_OID_DEFKEYID, 0x12000003),
+	[DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key),
+			       OID_FLAG_CACHED | OID_TYPE_KEY},	/* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */
+	OID_UNKNOWN(DOT11_OID_STAKEY, 0x12000008),
+	OID_U32(DOT11_OID_REKEYTHRESHOLD, 0x12000009),
+	OID_UNKNOWN(DOT11_OID_STASC, 0x1200000a),
+
+	OID_U32(DOT11_OID_PRIVTXREJECTED, 0x1a000000),
+	OID_U32(DOT11_OID_PRIVRXPLAIN, 0x1a000001),
+	OID_U32(DOT11_OID_PRIVRXFAILED, 0x1a000002),
+	OID_U32(DOT11_OID_PRIVRXNOKEY, 0x1a000003),
+
+	OID_U32_C(DOT11_OID_RTSTHRESH, 0x13000000),
+	OID_U32_C(DOT11_OID_FRAGTHRESH, 0x13000001),
+	OID_U32_C(DOT11_OID_SHORTRETRIES, 0x13000002),
+	OID_U32_C(DOT11_OID_LONGRETRIES, 0x13000003),
+	OID_U32_C(DOT11_OID_MAXTXLIFETIME, 0x13000004),
+	OID_U32(DOT11_OID_MAXRXLIFETIME, 0x13000005),
+	OID_U32(DOT11_OID_AUTHRESPTIMEOUT, 0x13000006),
+	OID_U32(DOT11_OID_ASSOCRESPTIMEOUT, 0x13000007),
+
+	OID_UNKNOWN(DOT11_OID_ALOFT_TABLE, 0x1d000000),
+	OID_UNKNOWN(DOT11_OID_ALOFT_CTRL_TABLE, 0x1d000001),
+	OID_UNKNOWN(DOT11_OID_ALOFT_RETREAT, 0x1d000002),
+	OID_UNKNOWN(DOT11_OID_ALOFT_PROGRESS, 0x1d000003),
+	OID_U32(DOT11_OID_ALOFT_FIXEDRATE, 0x1d000004),
+	OID_UNKNOWN(DOT11_OID_ALOFT_RSSIGRAPH, 0x1d000005),
+	OID_UNKNOWN(DOT11_OID_ALOFT_CONFIG, 0x1d000006),
 
 	[DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0},
-	[DOT11_OID_MAXFRAMEBURST] = OID_U32(0x1b000008), /* in microseconds */
+	OID_U32(DOT11_OID_MAXFRAMEBURST, 0x1b000008),
 
-	[DOT11_OID_PSM] = OID_U32(0x14000000),
-	[DOT11_OID_CAMTIMEOUT] = OID_U32(0x14000001),
-	[DOT11_OID_RECEIVEDTIMS] = OID_U32(0x14000002),
-	[DOT11_OID_ROAMPREFERENCE] = OID_U32(0x14000003),
-
-	[DOT11_OID_BRIDGELOCAL] = OID_U32(0x15000000),
-	[DOT11_OID_CLIENTS] = OID_U32(0x15000001),
-	[DOT11_OID_CLIENTSASSOCIATED] = OID_U32(0x15000002),
+	OID_U32(DOT11_OID_PSM, 0x14000000),
+	OID_U32(DOT11_OID_CAMTIMEOUT, 0x14000001),
+	OID_U32(DOT11_OID_RECEIVEDTIMS, 0x14000002),
+	OID_U32(DOT11_OID_ROAMPREFERENCE, 0x14000003),
+
+	OID_U32(DOT11_OID_BRIDGELOCAL, 0x15000000),
+	OID_U32(DOT11_OID_CLIENTS, 0x15000001),
+	OID_U32(DOT11_OID_CLIENTSASSOCIATED, 0x15000002),
 	[DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0},	/* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */
 
-	[DOT11_OID_CLIENTFIND] = OID_STRUCT(0x150007DB, u8[6]),
-	[DOT11_OID_WDSLINKADD] = OID_STRUCT(0x150007DC, u8[6]),
-	[DOT11_OID_WDSLINKREMOVE] = OID_STRUCT(0x150007DD, u8[6]),
-	[DOT11_OID_EAPAUTHSTA] = OID_STRUCT(0x150007DE, u8[6]),
-	[DOT11_OID_EAPUNAUTHSTA] = OID_STRUCT(0x150007DF, u8[6]),
-	[DOT11_OID_DOT1XENABLE] = OID_U32_C(0x150007E0),
-	[DOT11_OID_MICFAILURE] = OID_UNKNOWN(0x150007E1),
-	[DOT11_OID_REKEYINDICATE] = OID_UNKNOWN(0x150007E2),
-
-	[DOT11_OID_MPDUTXSUCCESSFUL] = OID_U32(0x16000000),
-	[DOT11_OID_MPDUTXONERETRY] = OID_U32(0x16000001),
-	[DOT11_OID_MPDUTXMULTIPLERETRIES] = OID_U32(0x16000002),
-	[DOT11_OID_MPDUTXFAILED] = OID_U32(0x16000003),
-	[DOT11_OID_MPDURXSUCCESSFUL] = OID_U32(0x16000004),
-	[DOT11_OID_MPDURXDUPS] = OID_U32(0x16000005),
-	[DOT11_OID_RTSSUCCESSFUL] = OID_U32(0x16000006),
-	[DOT11_OID_RTSFAILED] = OID_U32(0x16000007),
-	[DOT11_OID_ACKFAILED] = OID_U32(0x16000008),
-	[DOT11_OID_FRAMERECEIVES] = OID_U32(0x16000009),
-	[DOT11_OID_FRAMEERRORS] = OID_U32(0x1600000A),
-	[DOT11_OID_FRAMEABORTS] = OID_U32(0x1600000B),
-	[DOT11_OID_FRAMEABORTSPHY] = OID_U32(0x1600000C),
-
-	[DOT11_OID_SLOTTIME] = OID_U32(0x17000000),
-	[DOT11_OID_CWMIN] = OID_U32(0x17000001),
-	[DOT11_OID_CWMAX] = OID_U32(0x17000002),
-	[DOT11_OID_ACKWINDOW] = OID_U32(0x17000003),
-	[DOT11_OID_ANTENNARX] = OID_U32(0x17000004),
-	[DOT11_OID_ANTENNATX] = OID_U32(0x17000005),
-	[DOT11_OID_ANTENNADIVERSITY] = OID_U32(0x17000006),
-	[DOT11_OID_CHANNEL] = OID_U32_C(0x17000007),
-	[DOT11_OID_EDTHRESHOLD] = OID_U32_C(0x17000008),
-	[DOT11_OID_PREAMBLESETTINGS] = OID_U32(0x17000009),
-	[DOT11_OID_RATES] = OID_STRUCT(0x1700000A, u8[IWMAX_BITRATES + 1]),
-	[DOT11_OID_CCAMODESUPPORTED] = OID_U32(0x1700000B),
-	[DOT11_OID_CCAMODE] = OID_U32(0x1700000C),
-	[DOT11_OID_RSSIVECTOR] = OID_U32(0x1700000D),
-	[DOT11_OID_OUTPUTPOWERTABLE] = OID_U32(0x1700000E),
-	[DOT11_OID_OUTPUTPOWER] = OID_U32_C(0x1700000F),
-	[DOT11_OID_SUPPORTEDRATES] =
-	    OID_STRUCT(0x17000010, u8[IWMAX_BITRATES + 1]),
-	[DOT11_OID_FREQUENCY] = OID_U32_C(0x17000011),
-	[DOT11_OID_SUPPORTEDFREQUENCIES] = {0x17000012, 0, sizeof (struct
-								   obj_frequencies)
-					    + sizeof (u16) * IWMAX_FREQ, 0},
-
-	[DOT11_OID_NOISEFLOOR] = OID_U32(0x17000013),
-	[DOT11_OID_FREQUENCYACTIVITY] =
-	    OID_STRUCT(0x17000014, u8[IWMAX_FREQ + 1]),
-	[DOT11_OID_IQCALIBRATIONTABLE] = OID_UNKNOWN(0x17000015),
-	[DOT11_OID_NONERPPROTECTION] = OID_U32(0x17000016),
-	[DOT11_OID_SLOTSETTINGS] = OID_U32(0x17000017),
-	[DOT11_OID_NONERPTIMEOUT] = OID_U32(0x17000018),
-	[DOT11_OID_PROFILES] = OID_U32(0x17000019),
-	[DOT11_OID_EXTENDEDRATES] =
-	    OID_STRUCT(0x17000020, u8[IWMAX_BITRATES + 1]),
-
-	[DOT11_OID_DEAUTHENTICATE] = OID_STRUCT_MLME(0x18000000),
-	[DOT11_OID_AUTHENTICATE] = OID_STRUCT_MLME(0x18000001),
-	[DOT11_OID_DISASSOCIATE] = OID_STRUCT_MLME(0x18000002),
-	[DOT11_OID_ASSOCIATE] = OID_STRUCT_MLME(0x18000003),
-	[DOT11_OID_SCAN] = OID_UNKNOWN(0x18000004),
-	[DOT11_OID_BEACON] = OID_STRUCT_MLMEEX(0x18000005),
-	[DOT11_OID_PROBE] = OID_STRUCT_MLMEEX(0x18000006),
-	[DOT11_OID_DEAUTHENTICATEEX] = OID_STRUCT_MLMEEX(0x18000007),
-	[DOT11_OID_AUTHENTICATEEX] = OID_STRUCT_MLMEEX(0x18000008),
-	[DOT11_OID_DISASSOCIATEEX] = OID_STRUCT_MLMEEX(0x18000009),
-	[DOT11_OID_ASSOCIATEEX] = OID_STRUCT_MLMEEX(0x1800000A),
-	[DOT11_OID_REASSOCIATE] = OID_STRUCT_MLMEEX(0x1800000B),
-	[DOT11_OID_REASSOCIATEEX] = OID_STRUCT_MLMEEX(0x1800000C),
-
-	[DOT11_OID_NONERPSTATUS] = OID_U32(0x1E000000),
-
-	[DOT11_OID_STATIMEOUT] = OID_U32(0x19000000),
-	[DOT11_OID_MLMEAUTOLEVEL] = OID_U32_C(0x19000001),
-	[DOT11_OID_BSSTIMEOUT] = OID_U32(0x19000002),
-	[DOT11_OID_ATTACHMENT] = OID_UNKNOWN(0x19000003),
-	[DOT11_OID_PSMBUFFER] = OID_STRUCT_C(0x19000004, struct obj_buffer),
-
-	[DOT11_OID_BSSS] = OID_U32(0x1C000000),
-	[DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss), 0},	/*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */
-	[DOT11_OID_BSSFIND] = OID_STRUCT(0x1C000042, struct obj_bss),
+	OID_STRUCT(DOT11_OID_CLIENTFIND, 0x150007DB, u8[6], OID_TYPE_ADDR),
+	OID_STRUCT(DOT11_OID_WDSLINKADD, 0x150007DC, u8[6], OID_TYPE_ADDR),
+	OID_STRUCT(DOT11_OID_WDSLINKREMOVE, 0x150007DD, u8[6], OID_TYPE_ADDR),
+	OID_STRUCT(DOT11_OID_EAPAUTHSTA, 0x150007DE, u8[6], OID_TYPE_ADDR),
+	OID_STRUCT(DOT11_OID_EAPUNAUTHSTA, 0x150007DF, u8[6], OID_TYPE_ADDR),
+	OID_U32_C(DOT11_OID_DOT1XENABLE, 0x150007E0),
+	OID_UNKNOWN(DOT11_OID_MICFAILURE, 0x150007E1),
+	OID_UNKNOWN(DOT11_OID_REKEYINDICATE, 0x150007E2),
+
+	OID_U32(DOT11_OID_MPDUTXSUCCESSFUL, 0x16000000),
+	OID_U32(DOT11_OID_MPDUTXONERETRY, 0x16000001),
+	OID_U32(DOT11_OID_MPDUTXMULTIPLERETRIES, 0x16000002),
+	OID_U32(DOT11_OID_MPDUTXFAILED, 0x16000003),
+	OID_U32(DOT11_OID_MPDURXSUCCESSFUL, 0x16000004),
+	OID_U32(DOT11_OID_MPDURXDUPS, 0x16000005),
+	OID_U32(DOT11_OID_RTSSUCCESSFUL, 0x16000006),
+	OID_U32(DOT11_OID_RTSFAILED, 0x16000007),
+	OID_U32(DOT11_OID_ACKFAILED, 0x16000008),
+	OID_U32(DOT11_OID_FRAMERECEIVES, 0x16000009),
+	OID_U32(DOT11_OID_FRAMEERRORS, 0x1600000A),
+	OID_U32(DOT11_OID_FRAMEABORTS, 0x1600000B),
+	OID_U32(DOT11_OID_FRAMEABORTSPHY, 0x1600000C),
+
+	OID_U32(DOT11_OID_SLOTTIME, 0x17000000),
+	OID_U32(DOT11_OID_CWMIN, 0x17000001),
+	OID_U32(DOT11_OID_CWMAX, 0x17000002),
+	OID_U32(DOT11_OID_ACKWINDOW, 0x17000003),
+	OID_U32(DOT11_OID_ANTENNARX, 0x17000004),
+	OID_U32(DOT11_OID_ANTENNATX, 0x17000005),
+	OID_U32(DOT11_OID_ANTENNADIVERSITY, 0x17000006),
+	OID_U32_C(DOT11_OID_CHANNEL, 0x17000007),
+	OID_U32_C(DOT11_OID_EDTHRESHOLD, 0x17000008),
+	OID_U32(DOT11_OID_PREAMBLESETTINGS, 0x17000009),
+	OID_STRUCT(DOT11_OID_RATES, 0x1700000A, u8[IWMAX_BITRATES + 1],
+		   OID_TYPE_RAW),
+	OID_U32(DOT11_OID_CCAMODESUPPORTED, 0x1700000B),
+	OID_U32(DOT11_OID_CCAMODE, 0x1700000C),
+	OID_UNKNOWN(DOT11_OID_RSSIVECTOR, 0x1700000D),
+	OID_UNKNOWN(DOT11_OID_OUTPUTPOWERTABLE, 0x1700000E),
+	OID_U32(DOT11_OID_OUTPUTPOWER, 0x1700000F),
+	OID_STRUCT(DOT11_OID_SUPPORTEDRATES, 0x17000010,
+		   u8[IWMAX_BITRATES + 1], OID_TYPE_RAW),
+	OID_U32_C(DOT11_OID_FREQUENCY, 0x17000011),
+	[DOT11_OID_SUPPORTEDFREQUENCIES] =
+	    {0x17000012, 0, sizeof (struct obj_frequencies)
+	     + sizeof (u16) * IWMAX_FREQ, OID_TYPE_FREQUENCIES},
+
+	OID_U32(DOT11_OID_NOISEFLOOR, 0x17000013),
+	OID_STRUCT(DOT11_OID_FREQUENCYACTIVITY, 0x17000014, u8[IWMAX_FREQ + 1],
+		   OID_TYPE_RAW),
+	OID_UNKNOWN(DOT11_OID_IQCALIBRATIONTABLE, 0x17000015),
+	OID_U32(DOT11_OID_NONERPPROTECTION, 0x17000016),
+	OID_U32(DOT11_OID_SLOTSETTINGS, 0x17000017),
+	OID_U32(DOT11_OID_NONERPTIMEOUT, 0x17000018),
+	OID_U32(DOT11_OID_PROFILES, 0x17000019),
+	OID_STRUCT(DOT11_OID_EXTENDEDRATES, 0x17000020,
+		   u8[IWMAX_BITRATES + 1], OID_TYPE_RAW),
+
+	OID_STRUCT_MLME(DOT11_OID_DEAUTHENTICATE, 0x18000000),
+	OID_STRUCT_MLME(DOT11_OID_AUTHENTICATE, 0x18000001),
+	OID_STRUCT_MLME(DOT11_OID_DISASSOCIATE, 0x18000002),
+	OID_STRUCT_MLME(DOT11_OID_ASSOCIATE, 0x18000003),
+	OID_UNKNOWN(DOT11_OID_SCAN, 0x18000004),
+	OID_STRUCT_MLMEEX(DOT11_OID_BEACON, 0x18000005),
+	OID_STRUCT_MLMEEX(DOT11_OID_PROBE, 0x18000006),
+	OID_STRUCT_MLMEEX(DOT11_OID_DEAUTHENTICATEEX, 0x18000007),
+	OID_STRUCT_MLMEEX(DOT11_OID_AUTHENTICATEEX, 0x18000008),
+	OID_STRUCT_MLMEEX(DOT11_OID_DISASSOCIATEEX, 0x18000009),
+	OID_STRUCT_MLMEEX(DOT11_OID_ASSOCIATEEX, 0x1800000A),
+	OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATE, 0x1800000B),
+	OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATEEX, 0x1800000C),
+
+	OID_U32(DOT11_OID_NONERPSTATUS, 0x1E000000),
+
+	OID_U32(DOT11_OID_STATIMEOUT, 0x19000000),
+	OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001),
+	OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002),
+	OID_UNKNOWN(DOT11_OID_ATTACHMENT, 0x19000003),
+	OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer,
+		     OID_TYPE_BUFFER),
+
+	OID_U32(DOT11_OID_BSSS, 0x1C000000),
+	[DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss),
+			    OID_TYPE_BSS},	/*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */
+	OID_STRUCT(DOT11_OID_BSSFIND, 0x1C000042, struct obj_bss, OID_TYPE_BSS),
 	[DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct
 						      obj_bsslist) +
-			       sizeof (struct obj_bss[IWMAX_BSS]), 0},
+			       sizeof (struct obj_bss[IWMAX_BSS]),
+			       OID_TYPE_BSSLIST},
 
-	[OID_INL_TUNNEL] = OID_UNKNOWN(0xFF020000),
-	[OID_INL_MEMADDR] = OID_UNKNOWN(0xFF020001),
-	[OID_INL_MEMORY] = OID_UNKNOWN(0xFF020002),
-	[OID_INL_MODE] = OID_U32_C(0xFF020003),
-	[OID_INL_COMPONENT_NR] = OID_UNKNOWN(0xFF020004),
-	[OID_INL_VERSION] = OID_UNKNOWN(0xFF020005),
-	[OID_INL_INTERFACE_ID] = OID_UNKNOWN(0xFF020006),
-	[OID_INL_COMPONENT_ID] = OID_UNKNOWN(0xFF020007),
-	[OID_INL_CONFIG] = OID_U32_C(0xFF020008),
-	[OID_INL_DOT11D_CONFORMANCE] = OID_U32_C(0xFF02000C),
-	[OID_INL_PHYCAPABILITIES] = OID_U32(0xFF02000D),
-	[OID_INL_OUTPUTPOWER] = OID_U32_C(0xFF02000F),
+	OID_UNKNOWN(OID_INL_TUNNEL, 0xFF020000),
+	OID_UNKNOWN(OID_INL_MEMADDR, 0xFF020001),
+	OID_UNKNOWN(OID_INL_MEMORY, 0xFF020002),
+	OID_U32_C(OID_INL_MODE, 0xFF020003),
+	OID_UNKNOWN(OID_INL_COMPONENT_NR, 0xFF020004),
+	OID_UNKNOWN(OID_INL_VERSION, 0xFF020005),
+	OID_UNKNOWN(OID_INL_INTERFACE_ID, 0xFF020006),
+	OID_UNKNOWN(OID_INL_COMPONENT_ID, 0xFF020007),
+	OID_U32_C(OID_INL_CONFIG, 0xFF020008),
+	OID_U32_C(OID_INL_DOT11D_CONFORMANCE, 0xFF02000C),
+	OID_U32(OID_INL_PHYCAPABILITIES, 0xFF02000D),
+	OID_U32_C(OID_INL_OUTPUTPOWER, 0xFF02000F),
 
 };
 
@@ -257,6 +282,134 @@
 	priv->mib = NULL;
 }
 
+void
+mgt_le_to_cpu(int type, void *data)
+{
+	switch (type) {
+	case OID_TYPE_U32:
+		*(u32 *) data = le32_to_cpu(*(u32 *) data);
+		break;
+	case OID_TYPE_BUFFER:{
+			struct obj_buffer *buff = data;
+			buff->size = le32_to_cpu(buff->size);
+			buff->addr = le32_to_cpu(buff->addr);
+			break;
+		}
+	case OID_TYPE_BSS:{
+			struct obj_bss *bss = data;
+			bss->age = le16_to_cpu(bss->age);
+			bss->channel = le16_to_cpu(bss->channel);
+			bss->capinfo = le16_to_cpu(bss->capinfo);
+			bss->rates = le16_to_cpu(bss->rates);
+			bss->basic_rates = le16_to_cpu(bss->basic_rates);
+			break;
+		}
+	case OID_TYPE_BSSLIST:{
+			struct obj_bsslist *list = data;
+			int i;
+			list->nr = le32_to_cpu(list->nr);
+			for (i = 0; i < list->nr; i++)
+				mgt_le_to_cpu(OID_TYPE_BSS, &list->bsslist[i]);
+			break;
+		}
+	case OID_TYPE_FREQUENCIES:{
+			struct obj_frequencies *freq = data;
+			int i;
+			freq->nr = le16_to_cpu(freq->nr);
+			for (i = 0; i < freq->nr; i++)
+				freq->mhz[i] = le16_to_cpu(freq->mhz[i]);
+			break;
+		}
+	case OID_TYPE_MLME:{
+			struct obj_mlme *mlme = data;
+			mlme->id = le16_to_cpu(mlme->id);
+			mlme->state = le16_to_cpu(mlme->state);
+			mlme->code = le16_to_cpu(mlme->code);
+			break;
+		}
+	case OID_TYPE_MLMEEX:{
+			struct obj_mlmeex *mlme = data;
+			mlme->id = le16_to_cpu(mlme->id);
+			mlme->state = le16_to_cpu(mlme->state);
+			mlme->code = le16_to_cpu(mlme->code);
+			mlme->size = le16_to_cpu(mlme->size);
+			break;
+		}
+	case OID_TYPE_SSID:
+	case OID_TYPE_KEY:
+	case OID_TYPE_ADDR:
+	case OID_TYPE_RAW:
+		break;
+	default:
+		BUG();
+	}
+}
+
+static void
+mgt_cpu_to_le(int type, void *data)
+{
+	switch (type) {
+	case OID_TYPE_U32:
+		*(u32 *) data = cpu_to_le32(*(u32 *) data);
+		break;
+	case OID_TYPE_BUFFER:{
+			struct obj_buffer *buff = data;
+			buff->size = cpu_to_le32(buff->size);
+			buff->addr = cpu_to_le32(buff->addr);
+			break;
+		}
+	case OID_TYPE_BSS:{
+			struct obj_bss *bss = data;
+			bss->age = cpu_to_le16(bss->age);
+			bss->channel = cpu_to_le16(bss->channel);
+			bss->capinfo = cpu_to_le16(bss->capinfo);
+			bss->rates = cpu_to_le16(bss->rates);
+			bss->basic_rates = cpu_to_le16(bss->basic_rates);
+			break;
+		}
+	case OID_TYPE_BSSLIST:{
+			struct obj_bsslist *list = data;
+			int i;
+			list->nr = cpu_to_le32(list->nr);
+			for (i = 0; i < list->nr; i++)
+				mgt_cpu_to_le(OID_TYPE_BSS, &list->bsslist[i]);
+			break;
+		}
+	case OID_TYPE_FREQUENCIES:{
+			struct obj_frequencies *freq = data;
+			int i;
+			freq->nr = cpu_to_le16(freq->nr);
+			for (i = 0; i < freq->nr; i++)
+				freq->mhz[i] = cpu_to_le16(freq->mhz[i]);
+			break;
+		}
+	case OID_TYPE_MLME:{
+			struct obj_mlme *mlme = data;
+			mlme->id = cpu_to_le16(mlme->id);
+			mlme->state = cpu_to_le16(mlme->state);
+			mlme->code = cpu_to_le16(mlme->code);
+			break;
+		}
+	case OID_TYPE_MLMEEX:{
+			struct obj_mlmeex *mlme = data;
+			mlme->id = cpu_to_le16(mlme->id);
+			mlme->state = cpu_to_le16(mlme->state);
+			mlme->code = cpu_to_le16(mlme->code);
+			mlme->size = cpu_to_le16(mlme->size);
+			break;
+		}
+	case OID_TYPE_SSID:
+	case OID_TYPE_KEY:
+	case OID_TYPE_ADDR:
+	case OID_TYPE_RAW:
+		break;
+	default:
+		BUG();
+	}
+}
+
+/* Note : data is modified during this function */
+
 int
 mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
 {
@@ -265,7 +418,7 @@
 	int response_op = PIMFOR_OP_ERROR;
 	int dlen;
 	void *cache, *_data = data;
-	u32 oid, u;
+	u32 oid;
 
 	BUG_ON(OID_NUM_LAST <= n);
 	BUG_ON(extra > isl_oid[n].range);
@@ -279,13 +432,11 @@
 	cache += (cache ? extra * dlen : 0);
 	oid = isl_oid[n].oid + extra;
 
-	if (data == NULL)
+	if (_data == NULL)
 		/* we are requested to re-set a cached value */
 		_data = cache;
-	if ((isl_oid[n].flags & OID_FLAG_U32) && data) {
-		u = cpu_to_le32(*(u32 *) data);
-		_data = &u;
-	}
+	else
+		mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, _data);
 	/* If we are going to write to the cache, we don't want anyone to read
 	 * it -> acquire write lock.
 	 * Else we could acquire a read lock to be sure we don't bother the
@@ -295,7 +446,7 @@
 	if (cache)
 		down_write(&priv->mib_sem);
 
-	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+	if (islpci_get_state(priv) >= PRV_STATE_READY) {
 		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
 					     _data, dlen, &response);
 		if (!ret) {
@@ -303,7 +454,7 @@
 			islpci_mgt_release(response);
 		}
 		if (ret || response_op == PIMFOR_OP_ERROR)
-		        ret = -EIO;
+			ret = -EIO;
 	} else if (!cache)
 		ret = -EIO;
 
@@ -313,6 +464,10 @@
 		up_write(&priv->mib_sem);
 	}
 
+	/* re-set given data to what it was */
+	if (data)
+		mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data);
+
 	return ret;
 }
 
@@ -324,9 +479,9 @@
 	int ret = -EIO;
 	int reslen = 0;
 	struct islpci_mgmtframe *response = NULL;
-	
+
 	int dlen;
-	void *cache, *_res=NULL;
+	void *cache, *_res = NULL;
 	u32 oid;
 
 	BUG_ON(OID_NUM_LAST <= n);
@@ -345,11 +500,11 @@
 	if (cache)
 		down_read(&priv->mib_sem);
 
-	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+	if (islpci_get_state(priv) >= PRV_STATE_READY) {
 		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
 					     oid, data, dlen, &response);
 		if (ret || !response ||
-			response->header->operation == PIMFOR_OP_ERROR) {
+		    response->header->operation == PIMFOR_OP_ERROR) {
 			if (response)
 				islpci_mgt_release(response);
 			ret = -EIO;
@@ -362,20 +517,19 @@
 		_res = cache;
 		ret = 0;
 	}
-	if (isl_oid[n].flags & OID_FLAG_U32) {
-		if (ret)
-			res->u = 0;
-		else
-			res->u = le32_to_cpu(*(u32 *) _res);
-	} else {
+	if ((isl_oid[n].flags & OID_FLAG_TYPE) == OID_TYPE_U32)
+		res->u = ret ? 0 : le32_to_cpu(*(u32 *) _res);
+	else {
 		res->ptr = kmalloc(reslen, GFP_KERNEL);
 		BUG_ON(res->ptr == NULL);
 		if (ret)
 			memset(res->ptr, 0, reslen);
-		else
+		else {
 			memcpy(res->ptr, _res, reslen);
+			mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE,
+				      res->ptr);
+		}
 	}
-
 	if (cache)
 		up_read(&priv->mib_sem);
 
@@ -385,9 +539,9 @@
 	if (reslen > isl_oid[n].size)
 		printk(KERN_DEBUG
 		       "mgt_get_request(0x%x): received data length was bigger "
-		       "than expected (%d > %d). Memory is probably corrupted... ",
+		       "than expected (%d > %d). Memory is probably corrupted...",
 		       oid, reslen, isl_oid[n].size);
-	
+
 	return ret;
 }
 
@@ -404,14 +558,14 @@
 		int j = 0;
 		u32 oid = t->oid;
 		BUG_ON(data == NULL);
-		while (j <= t->range){
+		while (j <= t->range) {
 			response = NULL;
 			ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
-			                              oid, data, t->size,
+						      oid, data, t->size,
 						      &response);
 			if (response) {
 				ret |= (response->header->operation ==
-				        PIMFOR_OP_ERROR);
+					PIMFOR_OP_ERROR);
 				islpci_mgt_release(response);
 			}
 			j++;
@@ -431,13 +585,21 @@
 	BUG_ON(priv->mib[n] == NULL);
 
 	memcpy(priv->mib[n], data, isl_oid[n].size);
-	if (isl_oid[n].flags & OID_FLAG_U32)
-		*(u32 *) priv->mib[n] = cpu_to_le32(*(u32 *) priv->mib[n]);
+	mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, priv->mib[n]);
 }
 
-/* Commits the cache. If something goes wrong, it restarts the device. Lock
- * outside
- */
+void
+mgt_get(islpci_private *priv, enum oid_num_t n, void *res)
+{
+	BUG_ON(OID_NUM_LAST <= n);
+	BUG_ON(priv->mib[n] == NULL);
+	BUG_ON(res == NULL);
+
+	memcpy(res, priv->mib[n], isl_oid[n].size);
+	mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, res);
+}
+
+/* Commits the cache. Lock outside. */
 
 static enum oid_num_t commit_part1[] = {
 	OID_INL_CONFIG,
@@ -460,12 +622,32 @@
 	OID_INL_OUTPUTPOWER,
 };
 
+/* update the MAC addr. */
+static int
+mgt_update_addr(islpci_private *priv)
+{
+	struct islpci_mgmtframe *res;
+	int ret;
+
+	ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
+				     isl_oid[GEN_OID_MACADDRESS].oid, NULL,
+				     isl_oid[GEN_OID_MACADDRESS].size, &res);
+
+	if ((ret == 0) && res && (res->header->operation != PIMFOR_OP_ERROR))
+		memcpy(priv->ndev->dev_addr, res->data, 6);
+	else
+		ret = -EIO;
+	if (res)
+		islpci_mgt_release(res);
+
+	return ret;
+}
+
 void
 mgt_commit(islpci_private *priv)
 {
 	int rvalue;
 	u32 u;
-	union oid_res_t r;
 
 	if (islpci_get_state(priv) < PRV_STATE_INIT)
 		return;
@@ -481,21 +663,14 @@
 
 	u = OID_INL_MODE;
 	rvalue |= mgt_commit_list(priv, &u, 1);
+	rvalue |= mgt_update_addr(priv);
 
 	if (rvalue) {
 		/* some request have failed. The device might be in an
 		   incoherent state. We should reset it ! */
 		printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the "
-                "device \n", priv->ndev->name);
+		       "device \n", priv->ndev->name);
 	}
-
-	/* update the MAC addr. As it's not cached, no lock will be acquired by
-	 * the mgt_get_request
-	 */
-	mgt_get_request(priv, GEN_OID_MACADDRESS, 0, NULL, &r);
-	memcpy(priv->ndev->dev_addr, r.ptr, 6);
-	kfree(r.ptr);
-
 }
 
 /* This will tell you if you are allowed to answer a mlme(ex) request .*/
@@ -522,11 +697,116 @@
 {
 	int i;
 
-	for (i = 0; i < OID_NUM_LAST - 1; i++)
+	for (i = 0; i < OID_NUM_LAST; i++)
 		if (isl_oid[i].oid == oid)
 			return i;
 
 	printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid);
 
+	return OID_NUM_LAST;
+}
+
+int
+mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
+{
+	switch (isl_oid[n].flags & OID_FLAG_TYPE) {
+	case OID_TYPE_U32:
+		return snprintf(str, PRIV_STR_SIZE, "%u\n", r->u);
+		break;
+	case OID_TYPE_BUFFER:{
+			struct obj_buffer *buff = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"size=%u\naddr=0x%X\n", buff->size,
+					buff->addr);
+		}
+		break;
+	case OID_TYPE_BSS:{
+			struct obj_bss *bss = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"age=%u\nchannel=%u\n"
+					"capinfo=0x%X\nrates=0x%X\n"
+					"basic_rates=0x%X\n", bss->age,
+					bss->channel, bss->capinfo,
+					bss->rates, bss->basic_rates);
+		}
+		break;
+	case OID_TYPE_BSSLIST:{
+			struct obj_bsslist *list = r->ptr;
+			int i, k;
+			k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr);
+			for (i = 0; i < list->nr; i++)
+				k += snprintf(str + k, PRIV_STR_SIZE - k,
+					      "bss[%u] : \nage=%u\nchannel=%u\n"
+					      "capinfo=0x%X\nrates=0x%X\n"
+					      "basic_rates=0x%X\n",
+					      i, list->bsslist[i].age,
+					      list->bsslist[i].channel,
+					      list->bsslist[i].capinfo,
+					      list->bsslist[i].rates,
+					      list->bsslist[i].basic_rates);
+			return k;
+		}
+		break;
+	case OID_TYPE_FREQUENCIES:{
+			struct obj_frequencies *freq = r->ptr;
+			int i, t;
+			printk("nr : %u\n", freq->nr);
+			t = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", freq->nr);
+			for (i = 0; i < freq->nr; i++)
+				t += snprintf(str + t, PRIV_STR_SIZE - t,
+					      "mhz[%u]=%u\n", i, freq->mhz[i]);
+			return t;
+		}
+		break;
+	case OID_TYPE_MLME:{
+			struct obj_mlme *mlme = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"id=0x%X\nstate=0x%X\ncode=0x%X\n",
+					mlme->id, mlme->state, mlme->code);
+		}
+		break;
+	case OID_TYPE_MLMEEX:{
+			struct obj_mlmeex *mlme = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"id=0x%X\nstate=0x%X\n"
+					"code=0x%X\nsize=0x%X\n", mlme->id,
+					mlme->state, mlme->code, mlme->size);
+		}
+		break;
+	case OID_TYPE_SSID:{
+			struct obj_ssid *ssid = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"length=%u\noctets=%s\n",
+					ssid->length, ssid->octets);
+		}
+		break;
+	case OID_TYPE_KEY:{
+			struct obj_key *key = r->ptr;
+			int t, i;
+			t = snprintf(str, PRIV_STR_SIZE,
+				     "type=0x%X\nlength=0x%X\nkey=0x",
+				     key->type, key->length);
+			for (i = 0; i < key->length; i++)
+				t += snprintf(str + t, PRIV_STR_SIZE - t,
+					      "%02X:", key->key[i]);
+			t += snprintf(str + t, PRIV_STR_SIZE - t, "\n");
+			return t;
+		}
+		break;
+	case OID_TYPE_RAW:
+	case OID_TYPE_ADDR:{
+			unsigned char *buff = r->ptr;
+			int t, i;
+			t = snprintf(str, PRIV_STR_SIZE, "hex data=");
+			for (i = 0; i < isl_oid[n].size; i++)
+				t += snprintf(str + t, PRIV_STR_SIZE - t,
+					      "%02X:", buff[i]);
+			t += snprintf(str + t, PRIV_STR_SIZE - t, "\n");
+			return t;
+		}
+		break;
+	default:
+		BUG();
+	}
 	return 0;
 }
--- diff/drivers/net/wireless/prism54/oid_mgt.h	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/net/wireless/prism54/oid_mgt.h	2004-05-27 18:34:17.000000000 +0100
@@ -28,24 +28,31 @@
 
 void mgt_clean(islpci_private *);
 
+/* I don't know where to put these 3 */
 extern const int frequency_list_bg[];
-
 extern const int frequency_list_a[];
+int channel_of_freq(int);
+
+void mgt_le_to_cpu(int, void *);
 
 int mgt_set_request(islpci_private *, enum oid_num_t, int, void *);
 
 int mgt_get_request(islpci_private *, enum oid_num_t, int, void *,
-                    union oid_res_t *);
+		    union oid_res_t *);
 
 int mgt_commit_list(islpci_private *, enum oid_num_t *, int);
 
 void mgt_set(islpci_private *, enum oid_num_t, void *);
 
+void mgt_get(islpci_private *, enum oid_num_t, void *);
+
 void mgt_commit(islpci_private *);
 
 int mgt_mlme_answer(islpci_private *);
 
 enum oid_num_t mgt_oidtonum(u32 oid);
 
+int mgt_response_to_str(enum oid_num_t, union oid_res_t *, char *);
+
 #endif				/* !defined(_OID_MGT_H) */
 /* EOF */
--- diff/drivers/net/yellowfin.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/yellowfin.c	2004-05-27 18:34:17.000000000 +0100
@@ -1201,13 +1201,8 @@
 					break;
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-#if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb, rx_skb->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len), 
-					rx_skb->tail, pkt_len);
-#endif
 				pci_dma_sync_single_for_device(yp->pci_dev, desc->addr,
 											   yp->rx_buf_sz,
 											   PCI_DMA_FROMDEVICE);
--- diff/drivers/parisc/ccio-dma.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/parisc/ccio-dma.c	2004-05-27 18:34:17.000000000 +0100
@@ -44,7 +44,6 @@
 #include <asm/byteorder.h>
 #include <asm/cache.h>		/* for L1_CACHE_BYTES */
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/page.h>
 #include <asm/dma.h>
 #include <asm/io.h>
--- diff/drivers/parisc/ccio-rm-dma.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/parisc/ccio-rm-dma.c	2004-05-27 18:34:17.000000000 +0100
@@ -40,7 +40,6 @@
 #include <linux/pci.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
--- diff/drivers/pci/pci.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/pci/pci.c	2004-05-27 18:34:17.000000000 +0100
@@ -247,6 +247,8 @@
 	int pm;
 	u16 pmcsr;
 
+	might_sleep();
+
 	/* bound the state we're entering */
 	if (state > 3) state = 3;
 
--- diff/drivers/pcmcia/cs.c	2004-05-19 22:12:04.000000000 +0100
+++ source/drivers/pcmcia/cs.c	2004-05-27 18:34:17.000000000 +0100
@@ -789,9 +789,10 @@
 	    return 1;
     for (i = 0; i < MAX_IO_WIN; i++) {
 	if (s->io[i].NumPorts == 0) {
-	    if (find_io_region(base, num, align, name, s) == 0) {
+	    s->io[i].res = find_io_region(*base, num, align, name, s);
+	    if (s->io[i].res) {
 		s->io[i].Attributes = attr;
-		s->io[i].BasePort = *base;
+		s->io[i].BasePort = *base = s->io[i].res->start;
 		s->io[i].NumPorts = s->io[i].InUse = num;
 		break;
 	    } else
@@ -801,7 +802,8 @@
 	/* Try to extend top of window */
 	try = s->io[i].BasePort + s->io[i].NumPorts;
 	if ((*base == 0) || (*base == try))
-	    if (find_io_region(&try, num, 0, name, s) == 0) {
+	    if (adjust_io_region(s->io[i].res, s->io[i].res->start,
+				 s->io[i].res->end + num, s) == 0) {
 		*base = try;
 		s->io[i].NumPorts += num;
 		s->io[i].InUse += num;
@@ -810,7 +812,8 @@
 	/* Try to extend bottom of window */
 	try = s->io[i].BasePort - num;
 	if ((*base == 0) || (*base == try))
-	    if (find_io_region(&try, num, 0, name, s) == 0) {
+	    if (adjust_io_region(s->io[i].res, s->io[i].res->start - num,
+				 s->io[i].res->end, s) == 0) {
 		s->io[i].BasePort = *base = try;
 		s->io[i].NumPorts += num;
 		s->io[i].InUse += num;
@@ -824,15 +827,18 @@
 			     ioaddr_t num)
 {
     int i;
-    if(!(s->features & SS_CAP_STATIC_MAP))
-	release_region(base, num);
+
     for (i = 0; i < MAX_IO_WIN; i++) {
 	if ((s->io[i].BasePort <= base) &&
 	    (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
 	    s->io[i].InUse -= num;
 	    /* Free the window if no one else is using it */
-	    if (s->io[i].InUse == 0)
+	    if (s->io[i].InUse == 0) {
 		s->io[i].NumPorts = 0;
+		release_resource(s->io[i].res);
+		kfree(s->io[i].res);
+		s->io[i].res = NULL;
+	    }
 	}
     }
 }
--- diff/drivers/pcmcia/cs_internal.h	2004-05-19 22:12:04.000000000 +0100
+++ source/drivers/pcmcia/cs_internal.h	2004-05-27 18:34:17.000000000 +0100
@@ -181,8 +181,10 @@
 
 /* In rsrc_mgr */
 void validate_mem(struct pcmcia_socket *s);
-int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align,
+struct resource *find_io_region(unsigned long base, int num, unsigned long align,
 		   char *name, struct pcmcia_socket *s);
+int adjust_io_region(struct resource *res, unsigned long r_start,
+		     unsigned long r_end, struct pcmcia_socket *s);
 int find_mem_region(u_long *base, u_long num, u_long align,
 		    int low, char *name, struct pcmcia_socket *s);
 int try_irq(u_int Attributes, int irq, int specific);
--- diff/drivers/pcmcia/i82365.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/pcmcia/i82365.c	2004-05-27 18:34:17.000000000 +0100
@@ -1372,8 +1372,15 @@
 {
     int i, ret;
 
-    if (driver_register(&i82365_driver))
-	return -1;
+    ret = driver_register(&i82365_driver);
+    if (ret)
+	return ret;
+
+    ret = platform_device_register(&i82365_device);
+    if (ret) {
+	driver_unregister(&i82365_driver);
+	return ret;
+    }
 
     printk(KERN_INFO "Intel ISA PCIC probe: ");
     sockets = 0;
@@ -1382,12 +1389,11 @@
 
     if (sockets == 0) {
 	printk("not found.\n");
+	platform_device_unregister(&i82365_device);
 	driver_unregister(&i82365_driver);
 	return -ENODEV;
     }
 
-    platform_device_register(&i82365_device);
-
     /* Set up interrupt handler(s) */
     if (grab_irq != 0)
 	request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
--- diff/drivers/pcmcia/pxa2xx_lubbock.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/pcmcia/pxa2xx_lubbock.c	2004-05-27 18:34:17.000000000 +0100
@@ -20,9 +20,11 @@
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/hardware.h>
 #include <asm/hardware/sa1111.h>
+#include <asm/mach-types.h>
 
 #include "sa1111_generic.h"
 
@@ -30,156 +32,170 @@
 lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 				const socket_state_t *state)
 {
-  unsigned long flags, gpio, misc_wr;
-  int ret = 1;
-  struct pcmcia_state new_state;
-
-  local_irq_save(flags);
-
-  gpio = PA_DWR;
-  misc_wr = LUB_MISC_WR;
-
-  /* Lubbock uses the Maxim MAX1602, with the following connections:
-   *
-   * Socket 0 (PCMCIA):
-   *	MAX1602	Lubbock		Register
-   *	Pin	Signal
-   *	-----	-------		----------------------
-   *	A0VPP	S0_PWR0		SA-1111 GPIO A<0>
-   *	A1VPP	S0_PWR1		SA-1111 GPIO A<1>
-   *	A0VCC	S0_PWR2		SA-1111 GPIO A<2>
-   *	A1VCC	S0_PWR3		SA-1111 GPIO A<3>
-   *	VX	VCC
-   *	VY	+3.3V
-   *	12IN	+12V
-   *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
-   *
-   * Socket 1 (CF):
-   *	MAX1602	Lubbock		Register
-   *	Pin	Signal
-   *	-----	-------		----------------------
-   *	A0VPP	GND		VPP is not connected
-   *	A1VPP	GND		VPP is not connected
-   *	A0VCC	S1_PWR0		MISC_WR<14>
-   *	A1VCC	S1_PWR0		MISC_WR<15>
-   *	VX	VCC
-   *	VY	+3.3V
-   *	12IN	GND		VPP is not connected
-   *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
-   *
-   */
-
-again:
-  switch(skt->nr){
-  case 0:
-
-    switch(state->Vcc){
-    case 0:
-      gpio &= ~(GPIO_bit(2) | GPIO_bit(3));
-      break;
-
-    case 33:
-      gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(3);
-      break;
-
-    case 50:
-      gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
-      break;
-
-    default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc);
-      ret = -1;
-    }
-
-    switch(state->Vpp){
-    case 0:
-      gpio &= ~(GPIO_bit(0) | GPIO_bit(1));
-      break;
-
-    case 120:
-      gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(1);
-      break;
-
-    default:
-      /* REVISIT: I'm not sure about this? Is this correct?
-         Is it always safe or do we have potential problems
-         with bogus combinations of Vcc and Vpp settings? */
-      if(state->Vpp == state->Vcc)
-        gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(0);
-      else {
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, state->Vpp);
-	ret = -1;
-	break;
-      }
-    }
-
-    break;
-
-  case 1:
-    switch(state->Vcc){
-    case 0:
-      misc_wr &= ~((1 << 15) | (1 << 14));
-      break;
-
-    case 33:
-      misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
-      gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
-      break;
-
-    case 50:
-      misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
-      break;
-
-    default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc);
-      ret = -1;
-      break;
-    }
-
-    if(state->Vpp!=state->Vcc && state->Vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, state->Vpp);
-      ret = -1;
-      break;
-    }
-
-    break;
-
-  default:
-    ret = -1;
-  }
-
-  if (ret >= 0) {
-    sa1111_pcmcia_configure_socket(skt, state);
-    LUB_MISC_WR = misc_wr;
-    PA_DWR = gpio;
-  }
+	unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
+	int ret = 0;
+
+	pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
+
+	/* Lubbock uses the Maxim MAX1602, with the following connections:
+	 *
+	 * Socket 0 (PCMCIA):
+	 *	MAX1602	Lubbock		Register
+	 *	Pin	Signal
+	 *	-----	-------		----------------------
+	 *	A0VPP	S0_PWR0		SA-1111 GPIO A<0>
+	 *	A1VPP	S0_PWR1		SA-1111 GPIO A<1>
+	 *	A0VCC	S0_PWR2		SA-1111 GPIO A<2>
+	 *	A1VCC	S0_PWR3		SA-1111 GPIO A<3>
+	 *	VX	VCC
+	 *	VY	+3.3V
+	 *	12IN	+12V
+	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
+	 *
+	 * Socket 1 (CF):
+	 *	MAX1602	Lubbock		Register
+	 *	Pin	Signal
+	 *	-----	-------		----------------------
+	 *	A0VPP	GND		VPP is not connected
+	 *	A1VPP	GND		VPP is not connected
+	 *	A0VCC	S1_PWR0		MISC_WR<14>
+	 *	A1VCC	S1_PWR1		MISC_WR<15>
+	 *	VX	VCC
+	 *	VY	+3.3V
+	 *	12IN	GND		VPP is not connected
+	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
+	 *
+	 */
+
+ again:
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
+
+		switch (state->Vcc) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 33: /* VY */
+			pa_dwr_set |= GPIO_A3;
+			break;
+
+		case 50: /* VX */
+			pa_dwr_set |= GPIO_A2;
+			break;
+
+		default:
+			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			       __FUNCTION__, state->Vcc);
+			ret = -1;
+		}
+
+		switch (state->Vpp) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 120: /* 12IN */
+			pa_dwr_set |= GPIO_A1;
+			break;
+
+		default: /* VCC */
+			if (state->Vpp == state->Vcc)
+				pa_dwr_set |= GPIO_A0;
+			else {
+				printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
+				       __FUNCTION__, state->Vpp);
+				ret = -1;
+				break;
+			}
+		}
+		break;
+
+	case 1:
+		misc_mask = (1 << 15) | (1 << 14);
+
+		switch (state->Vcc) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 33: /* VY */
+			misc_set |= 1 << 15;
+			break;
+
+		case 50: /* VX */
+			misc_set |= 1 << 14;
+			break;
+
+		default:
+			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			       __FUNCTION__, state->Vcc);
+			ret = -1;
+			break;
+		}
+
+		if (state->Vpp != state->Vcc && state->Vpp != 0) {
+			printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
+			       __FUNCTION__, state->Vpp);
+			ret = -1;
+			break;
+		}
+		break;
+
+	default:
+		ret = -1;
+	}
+
+	if (ret == 0)
+		ret = sa1111_pcmcia_configure_socket(skt, state);
+
+	if (ret == 0) {
+		lubbock_set_misc_wr(misc_mask, misc_set);
+		sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, pa_dwr_set);
+	}
 
-  if (ret > 0) {
-    ret = 0;
 #if 1
-    /*
-     * HACK ALERT:
-     * We can't sense the voltage properly on Lubbock before actually
-     * applying some power to the socket (catch 22).
-     * Resense the socket Voltage Sense pins after applying socket power.
-     */
-    sa1111_pcmcia_socket_state(skt, &new_state);
-    if (state->Vcc == 33 && !new_state.vs_3v && !new_state.vs_Xv) {
-      /* Switch to 5V,  Configure socket with 5V voltage */
-      PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
-      PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
-      /* We need to hack around the const qualifier as well to keep this
-         ugly workaround localized and not force it to the rest of the code.
-         Barf bags avaliable in the seat pocket in front of you! */
-      ((socket_state_t *)state)->Vcc = 50;
-      ((socket_state_t *)state)->Vpp = 50;
-      goto again;
-    }
+	if (ret == 0 && state->Vcc == 33) {
+		struct pcmcia_state new_state;
+
+		/*
+		 * HACK ALERT:
+		 * We can't sense the voltage properly on Lubbock before
+		 * actually applying some power to the socket (catch 22).
+		 * Resense the socket Voltage Sense pins after applying
+		 * socket power.
+		 *
+		 * Note: It takes about 2.5ms for the MAX1602 VCC output
+		 * to rise.
+		 */
+		mdelay(3);
+
+		sa1111_pcmcia_socket_state(skt, &new_state);
+
+		if (!new_state.vs_3v && !new_state.vs_Xv) {
+			/*
+			 * Switch to 5V,  Configure socket with 5V voltage
+			 */
+			lubbock_set_misc_wr(misc_mask, 0);
+			sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, 0);
+
+			/*
+			 * It takes about 100ms to turn off Vcc.
+			 */
+			mdelay(100);
+
+			/*
+			 * We need to hack around the const qualifier as
+			 * well to keep this ugly workaround localized and
+			 * not force it to the rest of the code. Barf bags
+			 * avaliable in the seat pocket in front of you!
+			 */
+			((socket_state_t *)state)->Vcc = 50;
+			((socket_state_t *)state)->Vpp = 50;
+			goto again;
+		}
+	}
 #endif
-  }
 
-  local_irq_restore(flags);
-  return ret;
+	return ret;
 }
 
 static struct pcmcia_low_level lubbock_pcmcia_ops = {
@@ -196,7 +212,7 @@
 
 #include "pxa2xx_base.h"
 
-int __init pcmcia_lubbock_init(struct device *dev)
+int __init pcmcia_lubbock_init(struct sa1111_dev *sadev)
 {
 	int ret = -ENODEV;
 
@@ -205,16 +221,15 @@
 		 * Set GPIO_A<3:0> to be outputs for the MAX1600,
 		 * and switch to standby mode.
 		 */
-		PA_DWR = 0;
-		PA_DDR = 0;
-		PA_SDR = 0;
-		PA_SSR = 0;
+		sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
+		sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+		sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
 
 		/* Set CF Socket 1 power to standby mode. */
-		LUB_MISC_WR &= ~(GPIO_bit(15) | GPIO_bit(14));
+		lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
 
-		dev->platform_data = &lubbock_pcmcia_ops;
-		ret = pxa2xx_drv_pcmcia_probe(dev);
+		sadev->dev.platform_data = &lubbock_pcmcia_ops;
+		ret = pxa2xx_drv_pcmcia_probe(&sadev->dev);
 	}
 
 	return ret;
--- diff/drivers/pcmcia/rsrc_mgr.c	2004-05-19 22:12:04.000000000 +0100
+++ source/drivers/pcmcia/rsrc_mgr.c	2004-05-27 18:34:17.000000000 +0100
@@ -550,7 +550,7 @@
 
 	for (m = data->map->next; m != data->map; m = m->next) {
 		unsigned long start = m->base;
-		unsigned long end = m->base + m->num;
+		unsigned long end = m->base + m->num - 1;
 
 		/*
 		 * If the lower resources are not available, try aligning
@@ -569,7 +569,7 @@
 		if (res->start >= res->end)
 			break;
 
-		if ((res->start + size) <= end)
+		if ((res->start + size - 1) <= end)
 			break;
 	}
 
@@ -580,6 +580,32 @@
 		res->start = res->end;
 }
 
+/*
+ * Adjust an existing IO region allocation, but making sure that we don't
+ * encroach outside the resources which the user supplied.
+ */
+int adjust_io_region(struct resource *res, unsigned long r_start,
+		     unsigned long r_end, struct pcmcia_socket *s)
+{
+	resource_map_t *m;
+	int ret = -ENOMEM;
+
+	down(&rsrc_sem);
+	for (m = io_db.next; m != &io_db; m = m->next) {
+		unsigned long start = m->base;
+		unsigned long end = m->base + m->num - 1;
+
+		if (start > r_start || r_end > end)
+			continue;
+
+		ret = adjust_resource(res, r_start, r_end - r_start + 1);
+		break;
+	}
+	up(&rsrc_sem);
+
+	return ret;
+}
+
 /*======================================================================
 
     These find ranges of I/O ports or memory addresses that are not
@@ -593,40 +619,37 @@
     
 ======================================================================*/
 
-int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align,
-		   char *name, struct pcmcia_socket *s)
+struct resource *find_io_region(unsigned long base, int num,
+		   unsigned long align, char *name, struct pcmcia_socket *s)
 {
 	struct resource *res = make_resource(0, num, IORESOURCE_IO, name);
 	struct pcmcia_align_data data;
-	unsigned long min = *base;
+	unsigned long min = base;
 	int ret;
 
 	if (align == 0)
 		align = 0x10000;
 
 	data.mask = align - 1;
-	data.offset = *base & data.mask;
+	data.offset = base & data.mask;
 	data.map = &io_db;
 
+	down(&rsrc_sem);
 #ifdef CONFIG_PCI
 	if (s->cb_dev) {
 		ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
 					     min, 0, pcmcia_align, &data);
 	} else
 #endif
-	{
-		down(&rsrc_sem);
 		ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, 0,
 					pcmcia_align, &data);
-		up(&rsrc_sem);
-	}
+	up(&rsrc_sem);
 
 	if (ret != 0) {
 		kfree(res);
-	} else {
-		*base = res->start;
+		res = NULL;
 	}
-	return ret;
+	return res;
 }
 
 int find_mem_region(u_long *base, u_long num, u_long align,
@@ -652,6 +675,7 @@
 			min = 0x100000UL + *base;
 		}
 
+		down(&rsrc_sem);
 #ifdef CONFIG_PCI
 		if (s->cb_dev) {
 			ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
@@ -659,12 +683,9 @@
 						     pcmcia_align, &data);
 		} else
 #endif
-		{
-			down(&rsrc_sem);
 			ret = allocate_resource(&iomem_resource, res, num, min,
 						max, 0, pcmcia_align, &data);
-			up(&rsrc_sem);
-		}
+		up(&rsrc_sem);
 		if (ret == 0 || low)
 			break;
 		low = 1;
--- diff/drivers/pcmcia/sa1111_generic.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/pcmcia/sa1111_generic.c	2004-05-27 18:34:17.000000000 +0100
@@ -149,7 +149,7 @@
 	pcmcia_jornada720_init(&dev->dev);
 #endif
 #ifdef CONFIG_ARCH_LUBBOCK
-	pcmcia_lubbock_init(&dev->dev);
+	pcmcia_lubbock_init(dev);
 #endif
 #ifdef CONFIG_ASSABET_NEPONSET
 	pcmcia_neponset_init(dev);
--- diff/drivers/pcmcia/sa1111_generic.h	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/pcmcia/sa1111_generic.h	2004-05-27 18:34:17.000000000 +0100
@@ -10,6 +10,6 @@
 
 extern int pcmcia_badge4_init(struct device *);
 extern int pcmcia_jornada720_init(struct device *);
-extern int pcmcia_lubbock_init(struct device *);
+extern int pcmcia_lubbock_init(struct sa1111_dev *);
 extern int pcmcia_neponset_init(struct sa1111_dev *);
 
--- diff/drivers/pcmcia/soc_common.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/pcmcia/soc_common.c	2004-05-27 18:34:17.000000000 +0100
@@ -772,3 +772,39 @@
 
 	return 0;
 }
+	}
+
+	return 0;
+}
+
+static struct notifier_block sa1100_pcmcia_notifier_block = {
+	.notifier_call	= sa1100_pcmcia_notifier
+};
+
+static int __init sa11xx_pcmcia_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "SA11xx PCMCIA\n");
+
+	ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block,
+					CPUFREQ_TRANSITION_NOTIFIER);
+	if (ret < 0)
+		printk(KERN_ERR "Unable to register CPU frequency change "
+			"notifier (%d)\n", ret);
+
+	return ret;
+}
+module_init(sa11xx_pcmcia_init);
+
+static void __exit sa11xx_pcmcia_exit(void)
+{
+	cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+module_exit(sa11xx_pcmcia_exit);
+#endif
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver");
+MODULE_LICENSE("Dual MPL/GPL");
--- diff/drivers/pnp/isapnp/core.c	2004-05-19 22:12:04.000000000 +0100
+++ source/drivers/pnp/isapnp/core.c	2004-05-27 18:34:17.000000000 +0100
@@ -68,13 +68,8 @@
 MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_X86_PC9800
-#define _PIDXR		0x259
-#define _PNPWRP		0xa59
-#else
 #define _PIDXR		0x279
 #define _PNPWRP		0xa79
-#endif
 
 /* short tags */
 #define _STAG_PNPVERNO		0x01
--- diff/drivers/sbus/char/openprom.c	2004-05-19 22:12:07.000000000 +0100
+++ source/drivers/sbus/char/openprom.c	2004-05-27 18:34:17.000000000 +0100
@@ -149,7 +149,6 @@
 	char buffer[OPROMMAXPARAM+1], *buf;
 	struct openpromio *opp;
 	int bufsize, len, error = 0;
-	extern char saved_command_line[];
 	static int cnt;
 
 	if (cmd == OPROMSETOPT)
--- diff/drivers/scsi/Kconfig	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/scsi/Kconfig	2004-05-27 18:34:17.000000000 +0100
@@ -149,19 +149,8 @@
 	  can say Y here to force the SCSI driver to probe for multiple LUNs.
 	  A SCSI device with multiple LUNs acts logically like multiple SCSI
 	  devices. The vast majority of SCSI devices have only one LUN, and
-	  so most people can say N here and should in fact do so, because it
-	  is safer.
-
-config SCSI_REPORT_LUNS
-	bool "Build with SCSI REPORT LUNS support"
-	depends on SCSI
-	default y
-	help
-	  If you want support for SCSI REPORT LUNS, say Y here.
-	  The REPORT LUNS command is useful for devices (such as disk arrays)
-	  with large numbers of LUNs where the LUN values are not contiguous
-	  (sparse LUN).  REPORT LUNS scanning is done only for SCSI-3 devices.
-	  Most users can safely answer N here.
+	  so most people can say N here. The max_luns boot/module parameter 
+	  allows to override this setting.
 
 config SCSI_CONSTANTS
 	bool "Verbose SCSI error reporting (kernel size +=12K)"
@@ -238,7 +227,7 @@
 	depends on DECSTATION && SCSI
 
 config BLK_DEV_3W_XXXX_RAID
-	tristate "3ware Hardware ATA-RAID support"
+	tristate "3ware 5/6/7/8xxx ATA-RAID support"
 	depends on PCI && SCSI
 	help
 	  3ware is the only hardware ATA-Raid product in Linux to date.
@@ -250,6 +239,17 @@
 	  Please read the comments at the top of
 	  <file:drivers/scsi/3w-xxxx.c>.
 
+config SCSI_3W_9XXX
+	tristate "3ware 9xxx SATA-RAID support"
+	depends on PCI && SCSI
+	help
+	  This driver supports the 9000 series 3ware SATA-RAID cards.
+
+	  <http://www.amcc.com>
+
+	  Please read the comments at the top of
+	  <file:drivers/scsi/3w-9xxx.c>.
+
 config SCSI_7000FASST
 	tristate "7000FASST SCSI support"
 	depends on ISA && SCSI
@@ -363,7 +363,7 @@
 # All the I2O code and drivers do not seem to be 64bit safe.
 config SCSI_DPT_I2O
 	tristate "Adaptec I2O RAID support "
-	depends on !64BIT && SCSI && BROKEN
+	depends on !64BIT && SCSI
 	help
 	  This driver supports all of Adaptec's I2O based RAID controllers as 
 	  well as the DPT SmartRaid V cards.  This is an Adaptec maintained
@@ -989,7 +989,7 @@
 
 config SCSI_IPR
 	tristate "IBM Power Linux RAID adapter support"
-	depends on PCI && SCSI
+	depends on PCI && SCSI && PPC
 	select FW_LOADER
 	---help---
 	  This driver supports the IBM Power Linux family RAID adapters.
@@ -1721,18 +1721,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called esp.
 
-config SCSI_PC980155
-	tristate "NEC PC-9801-55 SCSI support"
-	depends on X86_PC9800 && SCSI
-	help
-	  If you have the NEC PC-9801-55 SCSI interface card or compatibles
-	  for NEC PC-9801/PC-9821, say Y.
-
-config WD33C93_PIO
-	bool
-	depends on SCSI_PC980155
-	default y
-
 #      bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
 
 config ZFCP
--- diff/drivers/scsi/Makefile	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/scsi/Makefile	2004-05-27 18:34:17.000000000 +0100
@@ -34,7 +34,6 @@
 obj-$(CONFIG_A3000_SCSI)	+= a3000.o	wd33c93.o
 obj-$(CONFIG_A2091_SCSI)	+= a2091.o	wd33c93.o
 obj-$(CONFIG_GVP11_SCSI)	+= gvp11.o	wd33c93.o
-obj-$(CONFIG_SCSI_PC980155)	+= pc980155.o	wd33c93.o
 obj-$(CONFIG_MVME147_SCSI)	+= mvme147.o	wd33c93.o
 obj-$(CONFIG_SGIWD93_SCSI)	+= sgiwd93.o	wd33c93.o
 obj-$(CONFIG_CYBERSTORM_SCSI)	+= NCR53C9x.o	cyberstorm.o
@@ -109,6 +108,7 @@
 obj-$(CONFIG_SCSI_PLUTO)	+= pluto.o
 obj-$(CONFIG_SCSI_DECNCR)	+= NCR53C9x.o	dec_esp.o
 obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
+obj-$(CONFIG_SCSI_3W_9XXX)	+= 3w-9xxx.o
 obj-$(CONFIG_SCSI_PPA)		+= ppa.o
 obj-$(CONFIG_SCSI_IMM)		+= imm.o
 obj-$(CONFIG_JAZZ_ESP)		+= NCR53C9x.o	jazz_esp.o
@@ -142,7 +142,6 @@
 				   scsi_devinfo.o
 scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
-scsi_mod-$(CONFIG_X86_PC9800)	+= scsi_pc98.o
 
 sd_mod-objs	:= sd.o
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
--- diff/drivers/scsi/NCR53c406a.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/NCR53c406a.c	2004-05-27 18:34:17.000000000 +0100
@@ -170,7 +170,6 @@
 /* Static function prototypes */
 static void NCR53c406a_intr(int, void *, struct pt_regs *);
 static irqreturn_t do_NCR53c406a_intr(int, void *, struct pt_regs *);
-static void wait_intr(void);
 static void chip_init(void);
 static void calc_port_addr(void);
 #ifndef IRQ_LEV
@@ -665,6 +664,7 @@
 	return (info_msg);
 }
 
+#if 0
 static void wait_intr(void)
 {
 	unsigned long i = jiffies + WATCHDOG;
@@ -684,6 +684,7 @@
 
 	NCR53c406a_intr(0, NULL, NULL);
 }
+#endif
 
 static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
--- diff/drivers/scsi/aacraid/README	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/aacraid/README	2004-05-27 18:34:17.000000000 +0100
@@ -38,15 +38,19 @@
 					(fixed 64bit and 64G memory model, changed confusing naming convention
 					 where fibs that go to the hardware are consistently called hw_fibs and
 					 not just fibs like the name of the driver tracking structure)
+Mark Salyzyn <Mark_Salyzyn@adaptec.com> Fixed panic issues and added some new product ids for upcoming hbas.
+
 Original Driver
 -------------------------
 Adaptec Unix OEM Product Group
 
 Mailing List
 -------------------------
-None currently. Also note this is very different to Brian's original driver
+linux-aacraid-devel@dell.com (Interested parties troll here)
+http://mbserver.adaptec.com/ (Currently more Community Support than Devel Support)
+Also note this is very different to Brian's original driver
 so don't expect him to support it.
-Adaptec does support this driver.  Contact either tech support or deanna bonds.
+Adaptec does support this driver.  Contact either tech support or Mark Salyzyn.
 
 Original by Brian Boerner February 2001
 Rewritten by Alan Cox, November 2001
--- diff/drivers/scsi/aacraid/aacraid.h	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/aacraid/aacraid.h	2004-05-27 18:34:17.000000000 +0100
@@ -1,18 +1,20 @@
-//#define dprintk(x) printk x
-#define dprintk(x)
+#if (!defined(dprintk))
+# define dprintk(x)
+#endif
 
 /*------------------------------------------------------------------------------
  *              D E F I N E S
  *----------------------------------------------------------------------------*/
+
 #define MAXIMUM_NUM_CONTAINERS	31
 #define MAXIMUM_NUM_ADAPTERS	8
 
-#define AAC_NUM_FIB	578
+#define AAC_NUM_FIB		578
 //#define AAC_NUM_IO_FIB	512
-#define AAC_NUM_IO_FIB	100
+#define AAC_NUM_IO_FIB		100
 
-#define AAC_MAX_TARGET (MAXIMUM_NUM_CONTAINERS+1)
-#define AAC_MAX_LUN	(8)
+#define AAC_MAX_TARGET 		(MAXIMUM_NUM_CONTAINERS+1)
+#define AAC_MAX_LUN		(8)
 
 #define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
 
@@ -241,92 +243,6 @@
 };
 
 /*
- * Implement our own version of these so we have 64 bit compatability
- * The adapter uses these and can only handle 32 bit addresses
- */
-
-struct aac_list_head {
-	u32 next;
-	u32 prev;
-};
-
-#define AAC_INIT_LIST_HEAD(ptr) do { \
-	(ptr)->next = (u32)(ulong)(ptr); \
-	(ptr)->prev = (u32)(ulong)(ptr); \
-} while (0)
-/**
- * aac_list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static __inline__ int aac_list_empty(struct aac_list_head *head)
-{
-	return head->next == ((u32)(ulong)head);
-}
-
-/*
- * Insert a new entry between two known consecutive entries. 
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static __inline__ void aac_list_add(struct aac_list_head * n,
-	struct aac_list_head * prev,
-	struct aac_list_head * next)
-{
-	next->prev = (u32)(ulong)n;
-	n->next = (u32)(ulong)next;
-	n->prev = (u32)(ulong)prev;
-	prev->next = (u32)(ulong)n;
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static __inline__ void aac_list_add_tail(struct aac_list_head *n, struct aac_list_head *head)
-{
-	aac_list_add(n, (struct aac_list_head*)(ulong)(head->prev), head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static __inline__ void __aac_list_del(struct aac_list_head * p,
-				  struct aac_list_head * n)
-{
-	n->prev = (u32)(ulong)p;
-	p->next = (u32)(ulong)n;
-}
-
-/**
- * aac_list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
- */
-static __inline__ void aac_list_del(struct aac_list_head *entry)
-{
-	__aac_list_del((struct aac_list_head*)(ulong)entry->prev,(struct aac_list_head*)(ulong) entry->next);
-	entry->next = entry->prev = 0;
-}
-
-/**
- * aac_list_entry - get the struct for this entry
- * @ptr:	the &struct list_head pointer.
- * @type:	the type of the struct this is embedded in.
- * @member:	the name of the list_struct within the struct.
- */
-#define aac_list_entry(ptr, type, member) \
-	((type *)((char *)(ptr)-(ulong)(&((type *)0)->member)))
-
-/*
  *	Assign type values to the FSA communication data structures
  */
 
@@ -339,11 +255,11 @@
 #define		FsaNormal	1
 #define		FsaHigh		2
 
-
 /*
  * Define the FIB. The FIB is the where all the requested data and
  * command information are put to the application on the FSA adapter.
  */
+
 struct aac_fibhdr {
 	u32 XferState;			// Current transfer state for this CCB
 	u16 Command;			// Routing information for the destination
@@ -359,13 +275,9 @@
 		    u32 _ReceiverTimeStart; 	// Timestamp for receipt of fib
 		    u32 _ReceiverTimeDone;	// Timestamp for completion of fib
 		} _s;
-		struct aac_list_head _FibLinks;	// Used to link Adapter Initiated Fibs on the host
-//		struct list_head _FibLinks;	// Used to link Adapter Initiated Fibs on the host
 	} _u;
 };
 
-#define FibLinks			_u._FibLinks
-
 #define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(struct aac_fibhdr))
 
 
@@ -558,12 +470,11 @@
 	spinlock_t		lockdata;	/* Actual lock (used only on one side of the lock) */
 	unsigned long		SavedIrql;     	/* Previous IRQL when the spin lock is taken */
 	u32			padding;	/* Padding - FIXME - can remove I believe */
-	struct aac_list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
-//	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
-                                		        /* only valid for command queues which receive entries from the adapter. */
-	struct list_head	pendingq;		/* A queue of outstanding fib's to the adapter. */
-	u32			numpending;		/* Number of entries on outstanding queue. */
-	struct aac_dev *	dev;			/* Back pointer to adapter structure */
+	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
+                                		/* only valid for command queues which receive entries from the adapter. */
+	struct list_head	pendingq;	/* A queue of outstanding fib's to the adapter. */
+	u32			numpending;	/* Number of entries on outstanding queue. */
+	struct aac_dev *	dev;		/* Back pointer to adapter structure */
 };
 
 /*
@@ -744,7 +655,7 @@
 	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
 	int			wait;		// Set to true when thread is in WaitForSingleObject
 	unsigned long		count;		// total number of FIBs on FibList
-	struct aac_list_head	hw_fib_list;	// this holds hw_fibs which should be 32 bit addresses
+	struct list_head	fib_list;	// this holds fibs and their attachd hw_fibs
 };
 
 struct fsa_scsi_hba {
@@ -781,7 +692,11 @@
 	 *	Outstanding I/O queue.
 	 */
 	struct list_head	queue;
-
+	/*
+	 *	And for the internal issue/reply queues (we may be able
+	 *	to merge these two)
+	 */
+	struct list_head	fiblink;
 	void 			*data;
 	struct hw_fib		*hw_fib;		/* Actual shared object */
 	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
@@ -836,19 +751,19 @@
 /*
  * Supported Options
  */
-#define AAC_OPT_SNAPSHOT	cpu_to_le32(1)
-#define AAC_OPT_CLUSTERS	cpu_to_le32(1<<1)
-#define AAC_OPT_WRITE_CACHE	cpu_to_le32(1<<2)
-#define AAC_OPT_64BIT_DATA	cpu_to_le32(1<<3)
-#define AAC_OPT_HOST_TIME_FIB	cpu_to_le32(1<<4)
-#define AAC_OPT_RAID50		cpu_to_le32(1<<5)
-#define AAC_OPT_4GB_WINDOW	cpu_to_le32(1<<6)
-#define AAC_OPT_SCSI_UPGRADEABLE cpu_to_le32(1<<7)
-#define AAC_OPT_SOFT_ERR_REPORT	cpu_to_le32(1<<8)
-#define AAC_OPT_SUPPORTED_RECONDITION cpu_to_le32(1<<9)
-#define AAC_OPT_SGMAP_HOST64	cpu_to_le32(1<<10)
-#define AAC_OPT_ALARM		cpu_to_le32(1<<11)
-#define AAC_OPT_NONDASD		cpu_to_le32(1<<12)
+#define AAC_OPT_SNAPSHOT		cpu_to_le32(1)
+#define AAC_OPT_CLUSTERS		cpu_to_le32(1<<1)
+#define AAC_OPT_WRITE_CACHE		cpu_to_le32(1<<2)
+#define AAC_OPT_64BIT_DATA		cpu_to_le32(1<<3)
+#define AAC_OPT_HOST_TIME_FIB		cpu_to_le32(1<<4)
+#define AAC_OPT_RAID50			cpu_to_le32(1<<5)
+#define AAC_OPT_4GB_WINDOW		cpu_to_le32(1<<6)
+#define AAC_OPT_SCSI_UPGRADEABLE 	cpu_to_le32(1<<7)
+#define AAC_OPT_SOFT_ERR_REPORT		cpu_to_le32(1<<8)
+#define AAC_OPT_SUPPORTED_RECONDITION 	cpu_to_le32(1<<9)
+#define AAC_OPT_SGMAP_HOST64		cpu_to_le32(1<<10)
+#define AAC_OPT_ALARM			cpu_to_le32(1<<11)
+#define AAC_OPT_NONDASD			cpu_to_le32(1<<12)
 
 struct aac_dev
 {
@@ -862,11 +777,10 @@
 	 */	
 	dma_addr_t		hw_fib_pa;
 	struct hw_fib		*hw_fib_va;
-	ulong			fib_base_va;
+	struct hw_fib		*aif_base_va;
 	/*
 	 *	Fib Headers
 	 */
-// dmb	struct fib              fibs[AAC_NUM_FIB]; /* Doing it here takes up too much from the scsi pool*/
 	struct fib              *fibs;
 
 	struct fib		*free_fib;
@@ -887,7 +801,6 @@
 	unsigned long		fsrev;		/* Main driver's revision number */
 	
 	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
-//	void *			init_pa; 	/* Holds physical address of the init struct */
 	dma_addr_t		init_pa; 	/* Holds physical address of the init struct */
 	
 	struct pci_dev		*pdev;		/* Our PCI interface */
@@ -898,7 +811,7 @@
 
 	struct Scsi_Host	*scsi_host_ptr;
 	struct fsa_scsi_hba	fsa_dev;
-	int			thread_pid;
+	pid_t			thread_pid;
 	int			cardtype;
 	
 	/*
--- diff/drivers/scsi/aacraid/commctrl.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/aacraid/commctrl.c	2004-05-27 18:34:17.000000000 +0100
@@ -148,7 +148,7 @@
 		 *	the list to 0.
 		 */
 		fibctx->count = 0;
-		AAC_INIT_LIST_HEAD(&fibctx->hw_fib_list);
+		INIT_LIST_HEAD(&fibctx->fib_list);
 		fibctx->jiffies = jiffies/HZ;
 		/*
 		 *	Now add this context onto the adapter's 
@@ -179,7 +179,7 @@
 {
 	struct fib_ioctl f;
 	struct aac_fib_context *fibctx, *aifcp;
-	struct hw_fib * hw_fib;
+	struct fib *fib;
 	int status;
 	struct list_head * entry;
 	int found;
@@ -222,25 +222,27 @@
 	 *	-EAGAIN
 	 */
 return_fib:
-	if (!aac_list_empty(&fibctx->hw_fib_list)) {
-		struct aac_list_head * entry;
+	if (!list_empty(&fibctx->fib_list)) {
+		struct list_head * entry;
 		/*
 		 *	Pull the next fib from the fibs
 		 */
-		entry = (struct aac_list_head*)(ulong)fibctx->hw_fib_list.next;
-		aac_list_del(entry);
+		entry = fibctx->fib_list.next;
+		list_del(entry);
 		
-		hw_fib = aac_list_entry(entry, struct hw_fib, header.FibLinks);
+		fib = list_entry(entry, struct fib, fiblink);
 		fibctx->count--;
 		spin_unlock_irqrestore(&dev->fib_lock, flags);
-		if (copy_to_user(f.fib, hw_fib, sizeof(struct hw_fib))) {
-			kfree(hw_fib);
+		if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) {
+			kfree(fib->hw_fib);
+			kfree(fib);
 			return -EFAULT;
 		}	
 		/*
 		 *	Free the space occupied by this copy of the fib.
 		 */
-		kfree(hw_fib);
+		kfree(fib->hw_fib);
+		kfree(fib);
 		status = 0;
 		fibctx->jiffies = jiffies/HZ;
 	} else {
@@ -262,24 +264,25 @@
 
 int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
 {
-	struct hw_fib *hw_fib;
+	struct fib *fib;
 
 	/*
 	 *	First free any FIBs that have not been consumed.
 	 */
-	while (!aac_list_empty(&fibctx->hw_fib_list)) {
-		struct aac_list_head * entry;
+	while (!list_empty(&fibctx->fib_list)) {
+		struct list_head * entry;
 		/*
 		 *	Pull the next fib from the fibs
 		 */
-		entry = (struct aac_list_head*)(ulong)(fibctx->hw_fib_list.next);
-		aac_list_del(entry);
-		hw_fib = aac_list_entry(entry, struct hw_fib, header.FibLinks);
+		entry = fibctx->fib_list.next;
+		list_del(entry);
+		fib = list_entry(entry, struct fib, fiblink);
 		fibctx->count--;
 		/*
 		 *	Free the space occupied by this copy of the fib.
 		 */
-		kfree(hw_fib);
+		kfree(fib->hw_fib);
+		kfree(fib);
 	}
 	/*
 	 *	Remove the Context from the AdapterFibContext List
--- diff/drivers/scsi/aacraid/comminit.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/aacraid/comminit.c	2004-05-27 18:34:17.000000000 +0100
@@ -81,9 +81,9 @@
 	 *	Adapter Fibs are the first thing allocated so that they
 	 *	start page aligned
 	 */
-	dev->fib_base_va = (ulong)base;
+	dev->aif_base_va = (struct hw_fib *)base;
 	
-	init->AdapterFibsVirtualAddress = cpu_to_le32((u32)(ulong)phys);
+	init->AdapterFibsVirtualAddress = cpu_to_le32(0);
 	init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
 	init->AdapterFibsSize = cpu_to_le32(fibsize);
 	init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
@@ -94,6 +94,9 @@
 	 * mapping system, but older Firmware did, and had *troubles* dealing
 	 * with the math overloading past 32 bits, thus we must limit this
 	 * field.
+	 *
+	 * FIXME: this assumes the memory is mapped zero->n, which isnt
+	 * always true on real computers.
 	 */
 	if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) {
 		init->HostPhysMemPages = 
@@ -140,7 +143,7 @@
 	q->dev = dev;
 	INIT_LIST_HEAD(&q->pendingq);
 	init_waitqueue_head(&q->cmdready);
-	AAC_INIT_LIST_HEAD(&q->cmdq);
+	INIT_LIST_HEAD(&q->cmdq);
 	init_waitqueue_head(&q->qfull);
 	spin_lock_init(&q->lockdata);
 	q->lock = &q->lockdata;
--- diff/drivers/scsi/aacraid/commsup.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/aacraid/commsup.c	2004-05-27 18:34:17.000000000 +0100
@@ -133,13 +133,10 @@
 	unsigned long flags;
 	spin_lock_irqsave(&dev->fib_lock, flags);
 	fibptr = dev->free_fib;	
-	while(!fibptr){
-		spin_unlock_irqrestore(&dev->fib_lock, flags);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-		spin_lock_irqsave(&dev->fib_lock, flags);
-		fibptr = dev->free_fib;	
-	}
+	/* Cannot sleep here or you get hangs. Instead we did the
+	   maths at compile time. */
+	if(!fibptr)
+		BUG();
 	dev->free_fib = fibptr->next;
 	spin_unlock_irqrestore(&dev->fib_lock, flags);
 	/*
@@ -290,7 +287,7 @@
 	}
 }   
 
-/*Command thread: *
+/**
  *	aac_queue_get		-	get the next free QE
  *	@dev: Adapter
  *	@index: Returned index
@@ -450,8 +447,7 @@
 	 *	Map the fib into 32bits by using the fib number
 	 */
 
-//	hw_fib->header.SenderFibAddress = ((u32)(fibptr-dev->fibs)) << 1;
-	hw_fib->header.SenderFibAddress = cpu_to_le32((u32)(ulong)fibptr->hw_fib_pa);
+	hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr-dev->fibs)) << 1);
 	hw_fib->header.SenderData = (u32)(fibptr - dev->fibs);
 	/*
 	 *	Set FIB state to indicate where it came from and if we want a
@@ -492,7 +488,7 @@
 	dprintk((KERN_DEBUG "  Command =               %d.\n", hw_fib->header.Command));
 	dprintk((KERN_DEBUG "  XferState  =            %x.\n", hw_fib->header.XferState));
 	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib));
-	dprintk((KERN_DEBUG "  hw_fib pa being sent=%xl\n",(ulong)fibptr->hw_fib_pa));
+	dprintk((KERN_DEBUG "  hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
 	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));
 	/*
 	 *	Fill in the Callback and CallbackContext if we are not
@@ -806,8 +802,8 @@
  
 int aac_command_thread(struct aac_dev * dev)
 {
-	struct hw_fib *hw_fib, *newfib;
-	struct fib fibptr; /* for error logging */
+	struct hw_fib *hw_fib, *hw_newfib;
+	struct fib *fib, *newfib;
 	struct aac_queue_block *queues = dev->queues;
 	struct aac_fib_context *fibctx;
 	unsigned long flags;
@@ -828,42 +824,44 @@
 	 *	Let the DPC know it has a place to send the AIF's to.
 	 */
 	dev->aif_thread = 1;
-	memset(&fibptr, 0, sizeof(struct fib));
 	add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	while(1) 
 	{
 		spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
-		while(!aac_list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
-			struct aac_list_head *entry;
+		while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
+			struct list_head *entry;
 			struct aac_aifcmd * aifcmd;
 
 			set_current_state(TASK_RUNNING);
 		
-			entry = (struct aac_list_head*)(ulong)(queues->queue[HostNormCmdQueue].cmdq.next);
-			dprintk(("aacraid: Command thread: removing fib from cmdq (%p)\n",entry));
-			aac_list_del(entry);
+			entry = queues->queue[HostNormCmdQueue].cmdq.next;
+			list_del(entry);
 			
 			spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
-			hw_fib = aac_list_entry(entry, struct hw_fib, header.FibLinks);
+			fib = list_entry(entry, struct fib, fiblink);
 			/*
 			 *	We will process the FIB here or pass it to a 
 			 *	worker thread that is TBD. We Really can't 
 			 *	do anything at this point since we don't have
 			 *	anything defined for this thread to do.
 			 */
-			memset(&fibptr, 0, sizeof(struct fib));
-			fibptr.type = FSAFS_NTC_FIB_CONTEXT;
-			fibptr.size = sizeof( struct fib );
-			fibptr.hw_fib = hw_fib;
-			fibptr.data = hw_fib->data;
-			fibptr.dev = dev;
+			hw_fib = fib->hw_fib;
+			memset(fib, 0, sizeof(struct fib));
+			fib->type = FSAFS_NTC_FIB_CONTEXT;
+			fib->size = sizeof( struct fib );
+			fib->hw_fib = hw_fib;
+			fib->data = hw_fib->data;
+			fib->dev = dev;
 			/*
 			 *	We only handle AifRequest fibs from the adapter.
 			 */
 			aifcmd = (struct aac_aifcmd *) hw_fib->data;
-			if (aifcmd->command == le16_to_cpu(AifCmdDriverNotify)) {
-				aac_handle_aif(dev, &fibptr);
+			if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) {
+				/* Handle Driver Notify Events */
+				aac_handle_aif(dev, fib);
+				*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
+				fib_adapter_complete(fib, sizeof(u32));
 			} else {
 				struct list_head *entry;
 				/* The u32 here is important and intended. We are using
@@ -872,6 +870,10 @@
 				u32 time_now, time_last;
 				unsigned long flagv;
 				
+				/* Sniff events */
+				if (aifcmd->command == cpu_to_le32(AifCmdEventNotify))
+					aac_handle_aif(dev, fib);
+				
 				time_now = jiffies/HZ;
 
 				spin_lock_irqsave(&dev->fib_lock, flagv);
@@ -893,6 +895,11 @@
 					 */
 					if (fibctx->count > 20)
 					{
+						/*
+						 * It's *not* jiffies folks,
+						 * but jiffies / HZ so do not
+						 * panic ...
+						 */
 						time_last = fibctx->jiffies;
 						/*
 						 * Has it been > 2 minutes 
@@ -909,17 +916,20 @@
 					 * Warning: no sleep allowed while
 					 * holding spinlock
 					 */
-					newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
-					if (newfib) {
+					hw_newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+					newfib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+					if (newfib && hw_newfib) {
 						/*
 						 * Make the copy of the FIB
 						 */
-						memcpy(newfib, hw_fib, sizeof(struct hw_fib));
+						memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib));
+						memcpy(newfib, fib, sizeof(struct fib));
+						newfib->hw_fib = hw_newfib;
 						/*
 						 * Put the FIB onto the
 						 * fibctx's fibs
 						 */
-						aac_list_add_tail(&newfib->header.FibLinks, &fibctx->hw_fib_list);
+						list_add_tail(&newfib->fiblink, &fibctx->fib_list);
 						fibctx->count++;
 						/* 
 						 * Set the event to wake up the
@@ -928,6 +938,10 @@
 						up(&fibctx->wait_sem);
 					} else {
 						printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
+						if(newfib)
+							kfree(newfib);
+						if(hw_newfib)
+							kfree(hw_newfib);
 					}
 					entry = entry->next;
 				}
@@ -935,10 +949,11 @@
 				 *	Set the status of this FIB
 				 */
 				*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
-				fib_adapter_complete(&fibptr, sizeof(u32));
+				fib_adapter_complete(fib, sizeof(u32));
 				spin_unlock_irqrestore(&dev->fib_lock, flagv);
 			}
 			spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
+			kfree(fib);
 		}
 		/*
 		 *	There are no more AIF's
--- diff/drivers/scsi/aacraid/dpcsup.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/aacraid/dpcsup.c	2004-05-27 18:34:17.000000000 +0100
@@ -70,12 +70,12 @@
 	 */
 	while(aac_consumer_get(dev, q, &entry))
 	{
-		u32 fast ;
-		fast = (entry->addr & cpu_to_le32(0x01));
-		hwfib = (struct hw_fib *)((char *)dev->hw_fib_va + 
-				((entry->addr & ~0x01) - dev->hw_fib_pa));
-		fib = &dev->fibs[hwfib->header.SenderData];
-
+		int fast;
+		u32 index = le32_to_cpu(entry->addr);
+		fast = index & 0x01;
+		fib = &dev->fibs[index >> 1];
+		hwfib = fib->hw_fib;
+		
 		aac_consumer_free(dev, q, HostNormRespQueue);
 		/*
 		 *	Remove this fib from the Outstanding I/O queue.
@@ -169,29 +169,44 @@
 	 */
 	while(aac_consumer_get(dev, q, &entry))
 	{
+		struct fib fibctx;
 		struct hw_fib * hw_fib;
-		hw_fib = (struct hw_fib *)((char *)dev->hw_fib_va + 
-				((entry->addr & ~0x01) - dev->hw_fib_pa));
-
-		if (dev->aif_thread) {
-		        aac_list_add_tail(&hw_fib->header.FibLinks, &q->cmdq);
+		u32 index;
+		struct fib *fib = &fibctx;
+		
+		index = le32_to_cpu(entry->addr) / sizeof(struct hw_fib);
+		hw_fib = &dev->aif_base_va[index];
+		
+		/*
+		 *	Allocate a FIB at all costs. For non queued stuff
+		 *	we can just use the stack so we are happy. We need
+		 *	a fib object in order to manage the linked lists
+		 */
+		if (dev->aif_thread)
+			if((fib = kmalloc(sizeof(struct fib), GFP_ATOMIC)) == NULL)
+				fib = &fibctx;
+		
+		memset(fib, 0, sizeof(struct fib));
+		INIT_LIST_HEAD(&fib->fiblink);
+		fib->type = FSAFS_NTC_FIB_CONTEXT;
+		fib->size = sizeof(struct fib);
+		fib->hw_fib = hw_fib;
+		fib->data = hw_fib->data;
+		fib->dev = dev;
+		
+				
+		if (dev->aif_thread && fib != &fibctx) {
+		        list_add_tail(&fib->fiblink, &q->cmdq);
 	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
 		        wake_up_interruptible(&q->cmdready);
 		} else {
-			struct fib fibctx;
 	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
 			spin_unlock_irqrestore(q->lock, flags);
-			memset(&fibctx, 0, sizeof(struct fib));
-			fibctx.type = FSAFS_NTC_FIB_CONTEXT;
-			fibctx.size = sizeof(struct fib);
-			fibctx.hw_fib = hw_fib;
-			fibctx.data = hw_fib->data;
-			fibctx.dev = dev;
 			/*
 			 *	Set the status of this FIB
 			 */
 			*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
-			fib_adapter_complete(&fibctx, sizeof(u32));
+			fib_adapter_complete(fib, sizeof(u32));
 			spin_lock_irqsave(q->lock, flags);
 		}		
 	}
--- diff/drivers/scsi/aacraid/sa.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/aacraid/sa.c	2004-05-27 18:34:17.000000000 +0100
@@ -419,6 +419,11 @@
 	 *	Start any kernel threads needed
 	 */
 	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	if (dev->thread_pid < 0) {
+		printk(KERN_ERR "aacraid: Unable to create command thread.\n");
+		return -1;
+	}
+
 	/*
 	 *	Tell the adapter that all is configure, and it can start 
 	 *	accepting requests
--- diff/drivers/scsi/advansys.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/advansys.c	2004-05-27 18:34:17.000000000 +0100
@@ -801,6 +801,7 @@
 #include <linux/blkdev.h>
 #include <linux/stat.h>
 #include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -4214,7 +4215,7 @@
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
-STATIC int        adv_get_sglist(asc_board_t *, adv_req_t *, Scsi_Cmnd *);
+STATIC int        adv_get_sglist(asc_board_t *, adv_req_t *, Scsi_Cmnd *, int);
 STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
 STATIC void       adv_async_callback(ADV_DVC_VAR *, uchar);
@@ -6381,9 +6382,30 @@
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
+	asc_board_t *boardp;
+	struct pci_dev *pci_dev;
+	int dir;
+
         ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp);
         tscp = REQPNEXT(scp);
         scp->host_scribble = NULL;
+
+	boardp = ASC_BOARDP(scp->device->host);
+
+	if (ASC_NARROW_BOARD(boardp))
+	    pci_dev = boardp->dvc_cfg.asc_dvc_cfg.pci_dev;
+	else
+	    pci_dev = boardp->dvc_cfg.adv_dvc_cfg.pci_dev;
+
+	dir = scsi_to_pci_dma_dir(scp->sc_data_direction);
+
+	if (scp->use_sg)
+	    pci_unmap_sg(pci_dev, (struct scatterlist *)scp->request_buffer,
+			 scp->use_sg, dir);
+	else if (scp->request_bufflen)
+	    pci_unmap_single(pci_dev, scp->SCp.dma_handle,
+			     scp->request_bufflen, dir);
+
         ASC_STATS(scp->device->host, done);
         ASC_ASSERT(scp->scsi_done != NULL);
 	if (from_isr)
@@ -6619,6 +6641,9 @@
 STATIC int
 asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp)
 {
+    struct pci_dev *pci_dev = boardp->dvc_cfg.asc_dvc_cfg.pci_dev;
+    int dir = scsi_to_pci_dma_dir(scp->sc_data_direction);
+
     /*
      * Mutually exclusive access is required to 'asc_scsi_q' and
      * 'asc_sg_head' until after the request is started.
@@ -6679,8 +6704,10 @@
          * CDB request of single contiguous buffer.
          */
         ASC_STATS(scp->device->host, cont_cnt);
-        asc_scsi_q.q1.data_addr =
-            cpu_to_le32(virt_to_bus(scp->request_buffer));
+	scp->SCp.dma_handle = scp->request_bufflen ?
+	    pci_map_single(pci_dev, scp->request_buffer,
+			   scp->request_bufflen, dir) : 0;
+	asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
         asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
         ASC_STATS_ADD(scp->device->host, cont_xfer,
                       ASC_CEILING(scp->request_bufflen, 512));
@@ -6691,12 +6718,17 @@
          * CDB scatter-gather request list.
          */
         int                     sgcnt;
+	int			use_sg;
         struct scatterlist      *slp;
 
-        if (scp->use_sg > scp->device->host->sg_tablesize) {
+	slp = (struct scatterlist *)scp->request_buffer;
+	use_sg = pci_map_sg(pci_dev, slp, scp->use_sg, dir);
+
+	if (use_sg > scp->device->host->sg_tablesize) {
             ASC_PRINT3(
 "asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
-                boardp->id, scp->use_sg, scp->device->host->sg_tablesize);
+		boardp->id, use_sg, scp->device->host->sg_tablesize);
+	    pci_unmap_sg(pci_dev, slp, scp->use_sg, dir);
             scp->result = HOST_BYTE(DID_ERROR);
             asc_enqueue(&boardp->done, scp, ASC_BACK);
             return ASC_ERROR;
@@ -6715,19 +6747,16 @@
         asc_scsi_q.q1.data_cnt = 0;
         asc_scsi_q.q1.data_addr = 0;
         /* This is a byte value, otherwise it would need to be swapped. */
-        asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
+	asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
         ASC_STATS_ADD(scp->device->host, sg_elem, asc_sg_head.entry_cnt);
 
         /*
          * Convert scatter-gather list into ASC_SG_HEAD list.
          */
-        slp = (struct scatterlist *) scp->request_buffer;
-        for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
-            asc_sg_head.sg_list[sgcnt].addr =
-                cpu_to_le32(virt_to_bus(
-		(unsigned char *)page_address(slp->page) + slp->offset));
-            asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
-            ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(slp->length, 512));
+	for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
+	    asc_sg_head.sg_list[sgcnt].addr = cpu_to_le32(sg_dma_address(slp));
+	    asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(sg_dma_len(slp));
+	    ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
         }
     }
 
@@ -6755,6 +6784,8 @@
     ADV_SCSI_REQ_Q      *scsiqp;
     int                 i;
     int                 ret;
+    struct pci_dev	*pci_dev = boardp->dvc_cfg.adv_dvc_cfg.pci_dev;
+    int			dir = scsi_to_pci_dma_dir(scp->sc_data_direction);
 
     /*
      * Allocate an adv_req_t structure from the board to execute
@@ -6827,15 +6858,23 @@
      * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
      * buffer command.
      */
-    scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
-    scsiqp->vdata_addr = scp->request_buffer;
-    scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
 
     if (scp->use_sg == 0) {
         /*
          * CDB request of single contiguous buffer.
          */
         reqp->sgblkp = NULL;
+	scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
+	if (scp->request_bufflen) {
+	    scsiqp->vdata_addr = scp->request_buffer;
+	    scp->SCp.dma_handle =
+	        pci_map_single(pci_dev, scp->request_buffer,
+			       scp->request_bufflen, dir);
+	} else {
+	    scsiqp->vdata_addr = 0;
+	    scp->SCp.dma_handle = 0;
+	}
+	scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
         scsiqp->sg_list_ptr = NULL;
         scsiqp->sg_real_addr = 0;
         ASC_STATS(scp->device->host, cont_cnt);
@@ -6845,10 +6884,21 @@
         /*
          * CDB scatter-gather request list.
          */
-        if (scp->use_sg > ADV_MAX_SG_LIST) {
+	struct scatterlist *slp;
+	int use_sg;
+
+	scsiqp->data_cnt = 0;
+	scsiqp->vdata_addr = 0;
+	scsiqp->data_addr = 0;
+
+	slp = (struct scatterlist *)scp->request_buffer;
+	use_sg = pci_map_sg(pci_dev, slp, scp->use_sg, dir);
+
+	if (use_sg > ADV_MAX_SG_LIST) {
             ASC_PRINT3(
 "adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
-                boardp->id, scp->use_sg, scp->device->host->sg_tablesize);
+		boardp->id, use_sg, scp->device->host->sg_tablesize);
+	    pci_unmap_sg(pci_dev, slp, scp->use_sg, dir);
             scp->result = HOST_BYTE(DID_ERROR);
             asc_enqueue(&boardp->done, scp, ASC_BACK);
 
@@ -6862,7 +6912,7 @@
             return ASC_ERROR;
         }
 
-        if ((ret = adv_get_sglist(boardp, reqp, scp)) != ADV_SUCCESS) {
+	if ((ret = adv_get_sglist(boardp, reqp, scp, use_sg)) != ADV_SUCCESS) {
             /*
              * Free the adv_req_t structure by adding it back to the
              * board free list.
@@ -6874,7 +6924,7 @@
         }
 
         ASC_STATS(scp->device->host, sg_cnt);
-        ASC_STATS_ADD(scp->device->host, sg_elem, scp->use_sg);
+	ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
     }
 
     ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
@@ -6898,7 +6948,7 @@
  *      ADV_ERROR(-1) - SG List creation failed
  */
 STATIC int
-adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp)
+adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp, int use_sg)
 {
     adv_sgblk_t         *sgblkp;
     ADV_SCSI_REQ_Q      *scsiqp;
@@ -6910,7 +6960,7 @@
 
     scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
     slp = (struct scatterlist *) scp->request_buffer;
-    sg_elem_cnt = scp->use_sg;
+    sg_elem_cnt = use_sg;
     prev_sg_block = NULL;
     reqp->sgblkp = NULL;
 
@@ -6982,11 +7032,9 @@
 
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
-            sg_block->sg_list[i].sg_addr =
-                cpu_to_le32(virt_to_bus(
-                   (unsigned char *)page_address(slp->page) + slp->offset));
-            sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
-            ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(slp->length, 512));
+	    sg_block->sg_list[i].sg_addr = cpu_to_le32(sg_dma_address(slp));
+	    sg_block->sg_list[i].sg_count = cpu_to_le32(sg_dma_len(slp));
+	    ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
 
             if (--sg_elem_cnt == 0)
             {   /* Last ADV_SG_BLOCK and scatter-gather entry. */
--- diff/drivers/scsi/atp870u.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/atp870u.c	2004-05-27 18:34:17.000000000 +0100
@@ -4,6 +4,7 @@
  *  Copyright (C) 1997	Wu Ching Chen
  *  2.1.x update (C) 1998  Krzysztof G. Baranowski
  *  2.5.x update (C) 2002  Red Hat <alan@redhat.com>
+ *  2.6.x update (C) 2004  Red Hat <alan@redhat.com>
  *
  * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes
  *
@@ -126,9 +127,11 @@
 			/*
 			 *      Issue more commands
 			 */
+			spin_lock_irqsave(dev->host->host_lock, flags);
 			if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) && (dev->in_snd == 0)) {
 				send_s870(host);
 			}
+			spin_unlock_irqrestore(dev->host->host_lock, flags);
 			/*
 			 *      Done
 			 */
@@ -371,9 +374,11 @@
 			/*
 			 *      If there is stuff to send and nothing going then send it
 			 */
+			spin_lock_irqsave(dev->host->host_lock, flags);
 			if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) && (dev->in_snd == 0)) {
 				send_s870(host);
 			}
+			spin_unlock_irqrestore(dev->host->host_lock, flags);
 			dev->in_int = 0;
 			goto out;
 		}
@@ -443,9 +448,16 @@
 	return IRQ_HANDLED;
 }
 
+/**
+ *	atp870u_queuecommand	-	Queue SCSI command
+ *	@req_p: request block
+ *	@done: completion function
+ *
+ *	Queue a command to the ATP queue. Called with the host lock held.
+ */
+ 
 static int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *))
 {
-	unsigned long flags;
 	unsigned short int m;
 	unsigned int tmport;
 	struct Scsi_Host *host;
@@ -484,7 +496,6 @@
 	 *      Count new command
 	 */
 
-	spin_lock_irqsave(host->host_lock, flags);
 	dev->quendu++;
 	if (dev->quendu >= qcnt) {
 		dev->quendu = 0;
@@ -498,24 +509,31 @@
 		}
 		dev->quendu--;
 		req_p->result = 0x00020000;
-		spin_unlock_irqrestore(host->host_lock, flags);
 		done(req_p);
 		return 0;
 	}
 	dev->querequ[dev->quendu] = req_p;
 	tmport = dev->ioport + 0x1c;
-	spin_unlock_irqrestore(host->host_lock, flags);
 	if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) {
 		send_s870(host);
 	}
 	return 0;
 }
 
+/**
+ *	send_s870	-	send a command to the controller
+ *	@host: host
+ *
+ *	On entry there is work queued to be done. We move some of that work to the
+ *	controller itself. 
+ *
+ *	Caller holds the host lock.
+ */
+ 
 static void send_s870(struct Scsi_Host *host)
 {
 	unsigned int tmport;
 	Scsi_Cmnd *workrequ;
-	unsigned long flags;
 	unsigned int i;
 	unsigned char j, target_id;
 	unsigned char *prd;
@@ -527,10 +545,7 @@
 	struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
 	int sg_count;
 
-	spin_lock_irqsave(host->host_lock, flags);
-	
 	if (dev->in_snd != 0) {
-		spin_unlock_irqrestore(host->host_lock, flags);
 		return;
 	}
 	dev->in_snd = 1;
@@ -543,13 +558,11 @@
 		dev->last_cmd = 0xff;
 		if (dev->quhdu == dev->quendu) {
 			dev->in_snd = 0;
-			spin_unlock_irqrestore(dev->host->host_lock, flags);
 			return;
 		}
 	}
 	if ((dev->last_cmd != 0xff) && (dev->working != 0)) {
 		dev->in_snd = 0;
-		spin_unlock_irqrestore(dev->host->host_lock, flags);
 		return;
 	}
 	dev->working++;
@@ -567,7 +580,6 @@
 	dev->quhdu = j;
 	dev->working--;
 	dev->in_snd = 0;
-	spin_unlock_irqrestore(host->host_lock, flags);
 	return;
 cmd_subp:
 	workportu = dev->ioport;
@@ -582,7 +594,6 @@
 abortsnd:
 	dev->last_cmd |= 0x40;
 	dev->in_snd = 0;
-	spin_unlock_irqrestore(dev->host->host_lock, flags);
 	return;
 oktosend:
 	memcpy(&dev->ata_cdbu[0], &workrequ->cmnd[0], workrequ->cmd_len);
@@ -684,7 +695,6 @@
 			dev->last_cmd |= 0x40;
 		}
 		dev->in_snd = 0;
-		spin_unlock_irqrestore(host->host_lock, flags);
 		return;
 	}
 	tmpcip = dev->pciport;
@@ -770,7 +780,6 @@
 			dev->last_cmd |= 0x40;
 		}
 		dev->in_snd = 0;
-		spin_unlock_irqrestore(host->host_lock, flags);
 		return;
 	}
 	if (inb(tmport) == 0) {
@@ -781,9 +790,6 @@
 		dev->last_cmd |= 0x40;
 	}
 	dev->in_snd = 0;
-	spin_unlock_irqrestore(host->host_lock, flags);
-	return;
-
 }
 
 static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
--- diff/drivers/scsi/dc390.h	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/dc390.h	2004-05-27 18:34:17.000000000 +0100
@@ -19,7 +19,7 @@
 #endif
 
 #define DC390_BANNER "Tekram DC390/AM53C974"
-#define DC390_VERSION "2.0f 2000-12-20"
+#define DC390_VERSION "2.1b 2004-04-13"
 
 /* We don't have eh_abort_handler, eh_device_reset_handler, 
  * eh_bus_reset_handler, eh_host_reset_handler yet! 
@@ -33,11 +33,11 @@
 # define USE_NEW_EH
 #endif
 
-extern int DC390_detect(Scsi_Host_Template *psht);
-extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
-extern int DC390_abort(Scsi_Cmnd *cmd);
-extern int DC390_reset(Scsi_Cmnd *cmd);
-extern int DC390_bios_param(struct scsi_device *sdev, struct block_device *dev,
+static int DC390_detect(Scsi_Host_Template *psht);
+static int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+static int DC390_abort(Scsi_Cmnd *cmd);
+static int DC390_reset(Scsi_Cmnd *cmd);
+static int DC390_bios_param(struct scsi_device *sdev, struct block_device *dev,
 		sector_t capacity, int geom[]);
 
 static int DC390_release(struct Scsi_Host *);
--- diff/drivers/scsi/dpt_i2o.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/scsi/dpt_i2o.c	2004-05-27 18:34:17.000000000 +0100
@@ -20,17 +20,21 @@
  *   (at your option) any later version.                                   *
  *                                                                         *
  ***************************************************************************/
+/***************************************************************************
+ * Sat Dec 20 2003 Go Taniguchi <go@turbolinux.co.jp>
+ - Support 2.6 kernel and DMA-mapping
+ - ioctl fix for raid tools
+ - use schedule_timeout in long long loop
+ **************************************************************************/
 
-//#define DEBUG 1
-//#define UARTDELAY 1
+/*#define DEBUG 1 */
+/*#define UARTDELAY 1 */
 
-// On the real kernel ADDR32 should always be zero for 2.4. GFP_HIGH allocates
-// high pages. Keep the macro around because of the broken unmerged ia64 tree
+/* On the real kernel ADDR32 should always be zero for 2.4. GFP_HIGH allocates
+   high pages. Keep the macro around because of the broken unmerged ia64 tree */
 
 #define ADDR32 (0)
 
-#error Please convert me to Documentation/DMA-mapping.txt
-
 #include <linux/version.h>
 #include <linux/module.h>
 
@@ -53,6 +57,7 @@
 #include <linux/kernel.h>	/* for printk */
 #include <linux/sched.h>
 #include <linux/reboot.h>
+#include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 
 #include <linux/timer.h>
@@ -85,7 +90,7 @@
 #elif defined(__alpha__)
 	PROC_ALPHA ,
 #else
-	(-1),(-1)
+	(-1),(-1),
 #endif
 	 FT_HBADRVR, 0, OEM_DPT, OS_LINUX, CAP_OVERLAP, DEV_ALL,
 	ADF_ALL_SC5, 0, 0, DPT_VERSION, DPT_REVISION, DPT_SUBREVISION,
@@ -226,7 +231,7 @@
 	/* Active IOPs now in OPERATIONAL state */
 	PDEBUG("HBA's in OPERATIONAL state\n");
 
-	printk(KERN_INFO"dpti: If you have a lot of devices this could take a few minutes.\n");
+	printk("dpti: If you have a lot of devices this could take a few minutes.\n");
 	for (pHba = hba_chain; pHba; pHba = pHba->next) {
 		printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name);
 		if (adpt_i2o_lct_get(pHba) < 0){
@@ -269,6 +274,7 @@
 	adpt_hba* pHba = (adpt_hba*) host->hostdata[0];
 //	adpt_i2o_quiesce_hba(pHba);
 	adpt_i2o_delete_hba(pHba);
+	scsi_unregister(host);
 	return 0;
 }
 
@@ -339,6 +345,8 @@
 	if (rcode != 0) {
 		sprintf(pHba->detail, "Adaptec I2O RAID");
 		printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode);
+		if (rcode != -ETIME && rcode != -EINTR)
+			kfree(buf);
 	} else {
 		memset(pHba->detail, 0, sizeof(pHba->detail));
 		memcpy(&(pHba->detail), "Vendor: Adaptec ", 16);
@@ -347,8 +355,8 @@
 		memcpy(&(pHba->detail[40]), " FW: ", 4);
 		memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4);
 		pHba->detail[48] = '\0';	/* precautionary */
+		kfree(buf);
 	}
-	kfree(buf);
 	adpt_i2o_status_get(pHba);
 	return ;
 }
@@ -478,7 +486,7 @@
 		heads = 255;
 		sectors = 63;
 	}
-	cylinders = capacity / (heads * sectors);
+	cylinders = sector_div(capacity, heads * sectors);
 
 	// Special case if CDROM
 	if(sdev->type == 5) {  // CDROM
@@ -871,6 +879,9 @@
 		return -EINVAL;
 	}
 	pci_set_master(pDev);
+	if (pci_set_dma_mask(pDev, 0xffffffffffffffffULL) &&
+	    pci_set_dma_mask(pDev, 0xffffffffULL))
+		return -EINVAL;
 
 	base_addr0_phys = pci_resource_start(pDev,0);
 	hba_map0_area_size = pci_resource_len(pDev,0);
@@ -963,6 +974,7 @@
 
 	// Initializing the spinlocks
 	spin_lock_init(&pHba->state_lock);
+	spin_lock_init(&adpt_post_wait_lock);
 
 	if(raptorFlag == 0){
 		printk(KERN_INFO"Adaptec I2O RAID controller %d at %lx size=%x irq=%d\n", 
@@ -1064,7 +1076,7 @@
 {
 	int i;
 
-	printk(KERN_INFO"Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
+	printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
 	for (i = 0; i < DPTI_MAX_HBA; i++) {
 		hbas[i] = NULL;
 	}
@@ -1152,12 +1164,22 @@
 	timeout *= HZ;
 	if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){
 		set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irq(pHba->host->host_lock);
+		if(pHba->host)
+			spin_unlock_irq(pHba->host->host_lock);
 		if (!timeout)
 			schedule();
-		else
+		else{
+			timeout = schedule_timeout(timeout);
+			if (timeout == 0) {
+				// I/O issued, but cannot get result in
+				// specified time. Freeing resorces is
+				// dangerous.
+				status = -ETIME;
+			}
 			schedule_timeout(timeout*HZ);
-		spin_lock_irq(pHba->host->host_lock);
+		}
+		if(pHba->host)
+			spin_lock_irq(pHba->host->host_lock);
 	}
 	spin_lock_irq(&adpt_wq_i2o_post.lock);
 	__remove_wait_queue(&adpt_wq_i2o_post, &wait);
@@ -1209,6 +1231,8 @@
 			printk(KERN_WARNING"dpti%d: Timeout waiting for message frame!\n", pHba->unit);
 			return -ETIMEDOUT;
 		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	} while(m == EMPTY_QUEUE);
 		
 	msg = (u32*) (pHba->msg_addr_virt + m);
@@ -1283,6 +1307,8 @@
 			printk(KERN_WARNING"Timeout waiting for message!\n");
 			return -ETIMEDOUT;
 		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	} while (m == EMPTY_QUEUE);
 
 	status = (u8*)kmalloc(4, GFP_KERNEL|ADDR32);
@@ -1314,6 +1340,8 @@
 			return -ETIMEDOUT;
 		}
 		rmb();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	}
 
 	if(*status == 0x01 /*I2O_EXEC_IOP_RESET_IN_PROGRESS*/) {
@@ -1330,6 +1358,8 @@
 				printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name);
 				return -ETIMEDOUT;
 			}
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
 		} while (m == EMPTY_QUEUE);
 		// Flush the offset
 		adpt_send_nop(pHba, m);
@@ -1695,15 +1725,20 @@
 	}
 
 	do {
-		spin_lock_irqsave(pHba->host->host_lock, flags);
+		if(pHba->host)
+			spin_lock_irqsave(pHba->host->host_lock, flags);
 		// This state stops any new commands from enterring the
 		// controller while processing the ioctl
 //		pHba->state |= DPTI_STATE_IOCTL;
 //		We can't set this now - The scsi subsystem sets host_blocked and
 //		the queue empties and stops.  We need a way to restart the queue
 		rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER);
+		if (rcode != 0)
+			printk("adpt_i2o_passthru: post wait failed %d %p\n",
+					rcode, reply);
 //		pHba->state &= ~DPTI_STATE_IOCTL;
-		spin_unlock_irqrestore(pHba->host->host_lock, flags);
+		if(pHba->host)
+			spin_unlock_irqrestore(pHba->host->host_lock, flags);
 	} while(rcode == -ETIMEDOUT);  
 
 	if(rcode){
@@ -1764,10 +1799,12 @@
 
 
 cleanup:
-	kfree (reply);
+	if (rcode != -ETIME && rcode != -EINTR)
+		kfree (reply);
 	while(sg_index) {
 		if(sg_list[--sg_index]) {
-			kfree((void*)(sg_list[sg_index]));
+			if (rcode != -ETIME && rcode != -EINTR)
+				kfree((void*)(sg_list[sg_index]));
 		}
 	}
 	return rcode;
@@ -1875,7 +1912,7 @@
 	int minor;
 	int error = 0;
 	adpt_hba* pHba;
-	ulong flags;
+	ulong flags = 0;
 
 	minor = iminor(inode);
 	if (minor >= DPTI_MAX_HBA){
@@ -1941,9 +1978,11 @@
 		break;
 		}
 	case I2ORESETCMD:
-		spin_lock_irqsave(pHba->host->host_lock, flags);
+		if(pHba->host)
+			spin_lock_irqsave(pHba->host->host_lock, flags);
 		adpt_hba_reset(pHba);
-		spin_unlock_irqrestore(pHba->host->host_lock, flags);
+		if(pHba->host)
+			spin_unlock_irqrestore(pHba->host->host_lock, flags);
 		break;
 	case I2ORESCANCMD:
 		adpt_rescan(pHba);
@@ -1956,7 +1995,7 @@
 }
 
 
-static void adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	Scsi_Cmnd* cmd;
 	adpt_hba* pHba = dev_id;
@@ -1965,12 +2004,15 @@
 	u32 status=0;
 	u32 context;
 	ulong flags = 0;
+	int handled = 0;
 
-	if (pHba == NULL ){
+	if (pHba == NULL){
 		printk(KERN_WARNING"adpt_isr: NULL dev_id\n");
-		return;
+		return IRQ_NONE;
 	}
-	spin_lock_irqsave(pHba->host->host_lock, flags);
+	if(pHba->host)
+		spin_lock_irqsave(pHba->host->host_lock, flags);
+
 	while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) {
 		m = readl(pHba->reply_port);
 		if(m == EMPTY_QUEUE){
@@ -2035,7 +2077,10 @@
 		wmb();
 		rmb();
 	}
-out:	spin_unlock_irqrestore(pHba->host->host_lock, flags);
+	handled = 1;
+out:	if(pHba->host)
+		spin_unlock_irqrestore(pHba->host->host_lock, flags);
+	return IRQ_RETVAL(handled);
 }
 
 static s32 adpt_scsi_to_i2o(adpt_hba* pHba, Scsi_Cmnd* cmd, struct adpt_device* d)
@@ -2110,15 +2155,19 @@
 	/* Now fill in the SGList and command */
 	if(cmd->use_sg) {
 		struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
+		int sg_count = pci_map_sg(pHba->pDev, sg, cmd->use_sg,
+                        scsi_to_pci_dma_dir(cmd->sc_data_direction));
+
+
 		len = 0;
-		for(i = 0 ; i < cmd->use_sg; i++) {
-			*mptr++ = direction|0x10000000|sg->length;
-			len+=sg->length;
-			*mptr++ = virt_to_bus(sg->address);
+		for(i = 0 ; i < sg_count; i++) {
+			*mptr++ = direction|0x10000000|sg_dma_len(sg);
+			len+=sg_dma_len(sg);
+			*mptr++ = sg_dma_address(sg);
 			sg++;
 		}
 		/* Make this an end of list */
-		mptr[-2] = direction|0xD0000000|(sg-1)->length;
+		mptr[-2] = direction|0xD0000000|sg_dma_len(sg-1);
 		reqlen = mptr - msg;
 		*lenptr = len;
 		
@@ -2132,7 +2181,10 @@
 			reqlen = 12;
 		} else {
 			*mptr++ = 0xD0000000|direction|cmd->request_bufflen;
-			*mptr++ = virt_to_bus(cmd->request_buffer);
+			*mptr++ = pci_map_single(pHba->pDev,
+				cmd->request_buffer,
+				cmd->request_bufflen,
+				scsi_to_pci_dma_dir(cmd->sc_data_direction));
 		}
 	}
 	
@@ -2305,15 +2357,17 @@
 static s32 adpt_rescan(adpt_hba* pHba)
 {
 	s32 rcode;
-	ulong flags;
+	ulong flags = 0;
 
-	spin_lock_irqsave(pHba->host->host_lock, flags);
+	if(pHba->host)
+		spin_lock_irqsave(pHba->host->host_lock, flags);
 	if ((rcode=adpt_i2o_lct_get(pHba)) < 0)
 		goto out;
 	if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0)
 		goto out;
 	rcode = 0;
-out:	spin_unlock_irqrestore(pHba->host->host_lock, flags);
+out:	if(pHba->host)
+		spin_unlock_irqrestore(pHba->host->host_lock, flags);
 	return rcode;
 }
 
@@ -2595,6 +2649,8 @@
 			printk(KERN_ERR "%s: Timeout waiting for message frame!\n",pHba->name);
 			return 2;
 		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	}
 	msg = (u32*)(pHba->msg_addr_virt + m);
 	writel( THREE_WORD_MSG_SIZE | SGL_OFFSET_0,&msg[0]);
@@ -2628,6 +2684,8 @@
 			printk(KERN_WARNING"%s: Timeout waiting for message frame\n",pHba->name);
 			return -ETIMEDOUT;
 		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	} while(m == EMPTY_QUEUE);
 
 	msg=(u32 *)(pHba->msg_addr_virt+m);
@@ -2663,9 +2721,10 @@
 		rmb();
 		if(time_after(jiffies,timeout)){
 			printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name);
-			kfree((void*)status);
 			return -ETIMEDOUT;
 		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	} while (1);
 
 	// If the command was successful, fill the fifo with our reply
@@ -2743,6 +2802,8 @@
 					pHba->name);
 			return -ETIMEDOUT;
 		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	} while(m==EMPTY_QUEUE);
 
 	
@@ -2769,6 +2830,8 @@
 			return -ETIMEDOUT;
 		}
 		rmb();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	}
 
 	// Set up our number of outbound and inbound messages
@@ -3094,17 +3157,33 @@
 			int group, int field, void *buf, int buflen)
 {
 	u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
-	u8  resblk[8+buflen]; /* 8 bytes for header */
+	u8 *resblk;
+
 	int size;
 
+	/* 8 bytes for header */
+	resblk = kmalloc(sizeof(u8) * (8+buflen), GFP_KERNEL|ADDR32);
+	if (resblk == NULL) {
+		printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name);
+		return -ENOMEM;
+	}
+
 	if (field == -1)  		/* whole group */
 			opblk[4] = -1;
 
 	size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid, 
-		opblk, sizeof(opblk), resblk, sizeof(resblk));
+		opblk, sizeof(opblk), resblk, sizeof(u8)*(8+buflen));
+	if (size == -ETIME) {
+		printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name);
+		return -ETIME;
+	} else if (size == -EINTR) {
+		printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name);
+		return -EINTR;
+	}
 			
 	memcpy(buf, resblk+8, buflen);  /* cut off header */
 
+	kfree(resblk);
 	if (size < 0)
 		return size;	
 
@@ -3138,6 +3217,7 @@
 	msg[8] = virt_to_bus(resblk);
 
 	if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) {
+		printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk);
    		return wait_status; 	/* -DetailedStatus */
 	}
 
--- diff/drivers/scsi/dpti.h	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/dpti.h	2004-05-27 18:34:17.000000000 +0100
@@ -65,7 +65,7 @@
 #include "dpt/dpti_i2o.h"
 #include "dpt/dpti_ioctl.h"
 
-#define DPT_I2O_VERSION "2.4 Build 5"
+#define DPT_I2O_VERSION "2.4 Build 5go"
 #define DPT_VERSION     2
 #define DPT_REVISION    '4'
 #define DPT_SUBREVISION '5'
@@ -272,7 +272,7 @@
 static void adpt_i2o_sys_shutdown(void);
 static int adpt_init(void);
 static int adpt_i2o_build_sys_table(void);
-static void adpt_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs);
 #ifdef REBOOT_NOTIFIER
 static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
 #endif
--- diff/drivers/scsi/gdth.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/gdth.c	2004-05-27 18:34:17.000000000 +0100
@@ -4,9 +4,9 @@
  * Intel Corporation:  Storage RAID Controllers                         *
  *                                                                      *
  * gdth.c                                                               *
- * Copyright (C) 1995-03 ICP vortex GmbH, Achim Leubner                 *
- * Copyright (C) 2002-03 Intel Corporation                              *
- * Copyright (C) 2003    Adaptec Inc.                                   *
+ * Copyright (C) 1995-04 ICP vortex GmbH, Achim Leubner                 *
+ * Copyright (C) 2002-04 Intel Corporation                              *
+ * Copyright (C) 2003-04 Adaptec Inc.                                   *
  * <achim_leubner@adaptec.com>                                          *
  *                                                                      *
  * Additions/Fixes:                                                     *
@@ -27,9 +27,42 @@
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.20, ..., 2.4.22                   *
+ * Linux kernel 2.2.x, 2.4.x, 2.6.x supported                           *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.73  2004/03/31 13:33:03  achim
+ * Special command 0xfd implemented to detect 64-bit DMA support
+ *
+ * Revision 1.72  2004/03/17 08:56:04  achim
+ * 64-bit DMA only enabled if FW >= x.43
+ *
+ * Revision 1.71  2004/03/05 15:51:29  achim
+ * Screen service: separate message buffer, bugfixes
+ *
+ * Revision 1.70  2004/02/27 12:19:07  achim
+ * Bugfix: Reset bit in config (0xfe) call removed
+ *
+ * Revision 1.69  2004/02/20 09:50:24  achim
+ * Compatibility changes for kernels < 2.4.20
+ * Bugfix screen service command size
+ * pci_set_dma_mask() error handling added
+ *
+ * Revision 1.68  2004/02/19 15:46:54  achim
+ * 64-bit DMA bugfixes
+ * Drive size bugfix for drives > 1TB
+ *
+ * Revision 1.67  2004/01/14 13:11:57  achim
+ * Tool access over /proc no longer supported
+ * Bugfixes IOCTLs
+ *
+ * Revision 1.66  2003/12/19 15:04:06  achim
+ * Bugfixes support for drives > 2TB
+ *
+ * Revision 1.65  2003/12/15 11:21:56  achim
+ * 64-bit DMA support added
+ * Support for drives > 2 TB implemented
+ * Kernels 2.2.x, 2.4.x, 2.6.x supported
+ *
  * Revision 1.64  2003/09/17 08:30:26  achim
  * EISA/ISA controller scan disabled
  * Command line switch probe_eisa_isa added
@@ -299,10 +332,12 @@
  * shared_access:N              enable driver reserve/release protocol
  * probe_eisa_isa:Y             scan for EISA/ISA controllers
  * probe_eisa_isa:N             do not scan for EISA/ISA controllers
+ * force_dma32:Y                use only 32 bit DMA mode
+ * force_dma32:N                use 64 bit DMA mode, if supported
  *
  * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
  *                          max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
- *                          shared_access:Y,probe_eisa_isa:N".
+ *                          shared_access:Y,probe_eisa_isa:N,force_dma32:N".
  * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
  * 
  * When loading the gdth driver as a module, the same options are available. 
@@ -313,7 +348,7 @@
  * 
  * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
  *           max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0 
- *           probe_eisa_isa=0"
+ *           probe_eisa_isa=0 force_dma32=0"
  * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
  */
 
@@ -330,9 +365,12 @@
  * phase:                   Service/parameter/return code special command
  */
 
-/* default: activate /proc and character device IOCTL interface */
-#define GDTH_IOCTL_PROC
-#define GDTH_IOCTL_CHRDEV
+
+/* interrupt coalescing */
+/* #define INT_COAL */
+
+/* statistics */
+#define GDTH_STATISTICS
 
 #include <linux/module.h>
 
@@ -353,35 +391,35 @@
 #ifdef GDTH_RTC
 #include <linux/mc146818rtc.h>
 #endif
-#if LINUX_VERSION_CODE >= 0x020100
 #include <linux/reboot.h>
-#else
-#include <linux/bios32.h>
-#endif
 
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 #include <linux/spinlock.h>
-#elif LINUX_VERSION_CODE >= 0x02015F
+#else
 #include <asm/spinlock.h>
 #endif
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #include <linux/blkdev.h>
-
-#include "scsi.h"
-#include "hosts.h"
-#if LINUX_VERSION_CODE < 0x020503
+#else
+#include <linux/blk.h>
 #include "sd.h"
 #endif
 
+#include "scsi.h"
+#include "hosts.h"
 #include "gdth.h"
 
 static void gdth_delay(int milliseconds);
-static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs);
+static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+#else
+static void gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+#endif
 static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
 static int gdth_async_event(int hanum);
 static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
@@ -419,31 +457,19 @@
 static void gdth_release_event(int hanum);
 static int gdth_wait(int hanum,int index,ulong32 time);
 static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
-                             ulong32 p2,ulong32 p3);
+                             ulong64 p2,ulong64 p3);
 static int gdth_search_drives(int hanum);
 static int gdth_analyse_hdrive(int hanum, ushort hdrive);
 
-static void *gdth_mmap(ulong paddr, ulong size);
-static void gdth_munmap(void *addr);
-
 static const char *gdth_ctr_name(int hanum);
 
-#ifdef GDTH_IOCTL_CHRDEV
 static int gdth_open(struct inode *inode, struct file *filep);
 static int gdth_close(struct inode *inode, struct file *filep);
 static int gdth_ioctl(struct inode *inode, struct file *filep,
                       unsigned int cmd, unsigned long arg);
-#endif
 
-#if LINUX_VERSION_CODE >= 0x010300
 static void gdth_flush(int hanum);
-#if LINUX_VERSION_CODE >= 0x020100
 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
-#else
-static int halt_called = FALSE;
-void gdth_halt(void);
-#endif
-#endif
 
 #ifdef DEBUG_GDTH
 static unchar   DebugState = DEBUG_GDTH;
@@ -528,6 +554,9 @@
 
 #ifdef GDTH_STATISTICS
 static ulong32 max_rq=0, max_index=0, max_sg=0;
+#ifdef INT_COAL
+static ulong32 max_int_coal=0;
+#endif
 static ulong32 act_ints=0, act_ios=0, act_stats=0, act_rq=0;
 static struct timer_list gdth_timer;
 #endif
@@ -542,80 +571,12 @@
 
 #define BUS_L2P(a,b)    ((b)>(a)->virt_bus ? (b-1):(b))
 
-#if LINUX_VERSION_CODE < 0x010300
-static void *gdth_mmap(ulong paddr, ulong size) 
-{
-    if (paddr >= high_memory)
-        return NULL; 
-    else
-        return (void *)paddr;
-}
-static void gdth_munmap(void *addr) 
-{
-}
-inline ulong32 virt_to_phys(volatile void *addr)
-{
-    return (ulong32)addr;
-}
-inline void *phys_to_virt(ulong32 addr)
-{
-    return (void *)addr;
-}
-#define virt_to_bus             virt_to_phys
-#define bus_to_virt             phys_to_virt
-#define gdth_readb(addr)        (*(volatile unchar *)(addr))
-#define gdth_readw(addr)        (*(volatile ushort *)(addr))
-#define gdth_readl(addr)        (*(volatile ulong32 *)(addr))
-#define gdth_writeb(b,addr)     (*(volatile unchar *)(addr) = (b))
-#define gdth_writew(b,addr)     (*(volatile ushort *)(addr) = (b))
-#define gdth_writel(b,addr)     (*(volatile ulong32 *)(addr) = (b))
-#define memset_io(a,b,c)        memset((void *)(a),(b),(c))
-#define memcpy_fromio(a,b,c)    memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c)      memcpy((void *)(a),(b),(c))
-
-#define PCI_SLOT(devfn)         ((devfn >> 3) & 0x1f)
-
-#elif LINUX_VERSION_CODE < 0x020100
-static int remapped = FALSE;
-static void *gdth_mmap(ulong paddr, ulong size) 
-{
-    if ( paddr >= high_memory) {
-        remapped = TRUE;
-        return vremap(paddr, size);
-    } else {
-        return (void *)paddr; 
-    }
-}
-static void gdth_munmap(void *addr) 
-{
-    if (remapped)
-        vfree(addr);
-    remapped = FALSE;
-}
-#define gdth_readb(addr)        readb((ulong)(addr))
-#define gdth_readw(addr)        readw((ulong)(addr))
-#define gdth_readl(addr)        (ulong32)readl((ulong)(addr))
-#define gdth_writeb(b,addr)     writeb((b),(ulong)(addr))
-#define gdth_writew(b,addr)     writew((b),(ulong)(addr))
-#define gdth_writel(b,addr)     writel((ulong32)(b),(ulong)(addr))
-
-#else
-static void *gdth_mmap(ulong paddr, ulong size) 
-{ 
-    return ioremap(paddr, size); 
-}
-static void gdth_munmap(void *addr) 
-{
-    return iounmap(addr);
-}
 #define gdth_readb(addr)        readb((ulong)(addr))
 #define gdth_readw(addr)        readw((ulong)(addr))
 #define gdth_readl(addr)        (ulong32)readl((ulong)(addr))
 #define gdth_writeb(b,addr)     writeb((b),(ulong)(addr))
 #define gdth_writew(b,addr)     writew((b),(ulong)(addr))
 #define gdth_writel(b,addr)     writel((ulong32)(b),(ulong)(addr))
-#endif
-
 
 static unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
 static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
@@ -631,9 +592,7 @@
 static gdth_evt_str ebuffer[MAX_EVENTS];                /* event buffer */
 static int elastidx;
 static int eoldidx;
-#ifdef GDTH_IOCTL_CHRDEV
 static int major;
-#endif
 
 #define DIN     1                               /* IN data direction */
 #define DOU     2                               /* OUT data direction */
@@ -648,8 +607,8 @@
     DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
-    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
-    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,
     DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU,
     DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
@@ -659,47 +618,32 @@
 };
 
 /* __initfunc, __initdata macros */
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define __devinitdata
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 #define GDTH_INITFUNC(type, func)       type __init func 
 #include <linux/init.h>
-#elif LINUX_VERSION_CODE >= 0x020126
+#else
 #define GDTH_INITFUNC(type, func)       __initfunc(type func)
 #include <linux/init.h>
-#else
-#define GDTH_INITFUNC(type, func)       type func
-#define __initdata
-#define __init
 #endif
 
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #define GDTH_INIT_LOCK_HA(ha)           spin_lock_init(&(ha)->smp_lock)
 #define GDTH_LOCK_HA(ha,flags)          spin_lock_irqsave(&(ha)->smp_lock,flags)
 #define GDTH_UNLOCK_HA(ha,flags)        spin_unlock_irqrestore(&(ha)->smp_lock,flags)
 
 #define GDTH_LOCK_SCSI_DONE(dev, flags) spin_lock_irqsave(dev->host_lock,flags)
 #define GDTH_UNLOCK_SCSI_DONE(dev, flags) spin_unlock_irqrestore(dev->host_lock,flags)
-#define GDTH_LOCK_SCSI_DOCMD(dev)       spin_lock_irq(dev->host_lock)
-#define GDTH_UNLOCK_SCSI_DOCMD(dev)     spin_unlock_irq(dev->host_lock)
 
-#elif LINUX_VERSION_CODE >= 0x02015F
+#else
 #define GDTH_INIT_LOCK_HA(ha)           spin_lock_init(&(ha)->smp_lock)
 #define GDTH_LOCK_HA(ha,flags)          spin_lock_irqsave(&(ha)->smp_lock,flags)
 #define GDTH_UNLOCK_HA(ha,flags)        spin_unlock_irqrestore(&(ha)->smp_lock,flags)
 
 #define GDTH_LOCK_SCSI_DONE(flags)      spin_lock_irqsave(&io_request_lock,flags)
 #define GDTH_UNLOCK_SCSI_DONE(flags)    spin_unlock_irqrestore(&io_request_lock,flags)
-#define GDTH_LOCK_SCSI_DOCMD()          spin_lock_irq(&io_request_lock)
-#define GDTH_UNLOCK_SCSI_DOCMD()        spin_unlock_irq(&io_request_lock)
-
-#else
-#define GDTH_INIT_LOCK_HA(ha)           do {} while (0)
-#define GDTH_LOCK_HA(ha,flags)          do {save_flags(flags); cli();} while (0)
-#define GDTH_UNLOCK_HA(ha,flags)        do {restore_flags(flags);} while (0)
-
-#define GDTH_LOCK_SCSI_DONE(flags)      do {} while (0)
-#define GDTH_UNLOCK_SCSI_DONE(flags)    do {} while (0)
-#define GDTH_LOCK_SCSI_DOCMD()          do {} while (0)
-#define GDTH_UNLOCK_SCSI_DOCMD()        do {} while (0)
 #endif
 
 /* LILO and modprobe/insmod parameters */
@@ -730,9 +674,10 @@
 static int shared_access = 1;
 /* enable support for EISA and ISA controllers */
 static int probe_eisa_isa = 0;
+/* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */
+static int force_dma32 = 0;
 
 #ifdef MODULE
-#if LINUX_VERSION_CODE >= 0x02011A
 /* parameters for modprobe/insmod */
 MODULE_PARM(irq, "i");
 MODULE_PARM(disable, "i");
@@ -745,41 +690,42 @@
 MODULE_PARM(virt_ctr, "i");
 MODULE_PARM(shared_access, "i");
 MODULE_PARM(probe_eisa_isa, "i");
+MODULE_PARM(force_dma32, "i");
 MODULE_AUTHOR("Achim Leubner");
-#endif
-#if LINUX_VERSION_CODE >= 0x02040B
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,11)
 MODULE_LICENSE("GPL");
 #endif
 #endif
 
-#ifdef GDTH_IOCTL_CHRDEV
 /* ioctl interface */
 static struct file_operations gdth_fops = {
-	.ioctl		= gdth_ioctl,
-	.open		= gdth_open,
-	.release	= gdth_close,
-};
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    .ioctl   = gdth_ioctl,
+    .open    = gdth_open,
+    .release = gdth_close,
+#else
+    ioctl:gdth_ioctl,
+    open:gdth_open,
+    release:gdth_close,
 #endif
+};
 
 /* /proc support */
-#if LINUX_VERSION_CODE >= 0x010300
 #include <linux/stat.h> 
-#if LINUX_VERSION_CODE < 0x020322
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 struct proc_dir_entry proc_scsi_gdth = {
     PROC_SCSI_GDTH, 4, "gdth",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 #endif
+
 #include "gdth_proc.h"
 #include "gdth_proc.c"
-#endif
 
-#if LINUX_VERSION_CODE >= 0x020100
 /* notifier block to get a notify on system shutdown/halt/reboot */
 static struct notifier_block gdth_notifier = {
     gdth_halt, NULL, 0
 };
-#endif
 
 
 static void gdth_delay(int milliseconds)
@@ -787,17 +733,11 @@
     if (milliseconds == 0) {
         udelay(1);
     } else {
-#if LINUX_VERSION_CODE >= 0x020168
         mdelay(milliseconds);
-#else
-        int i;
-        for (i = 0; i < milliseconds; ++i) 
-            udelay(1000);
-#endif
     }
 }
 
-static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs)
+static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs)
 {
     *cyls = size /HEADS/SECS;
     if (*cyls <= MAXCYLS) {
@@ -842,9 +782,9 @@
     ulong32 id;
 
     TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr));
-    if ((addr = gdth_mmap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
+    if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
         id = gdth_readl(addr);
-        gdth_munmap(addr);
+        iounmap(addr);
         if (id == GDT2_ID)                          /* GDT2000 */
             return 1;
     }
@@ -866,6 +806,8 @@
         gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, device);
     gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, 
                     PCI_DEVICE_ID_VORTEX_GDTNEWRX);
+    gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, 
+                    PCI_DEVICE_ID_VORTEX_GDTNEWRX2);
     gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL,
                     PCI_DEVICE_ID_INTEL_SRC);
     gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL,
@@ -873,11 +815,11 @@
     return cnt;
 }
 
-#if LINUX_VERSION_CODE >= 0x20363
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 /* Vortex only makes RAID controllers.
  * We do not really want to specify all 550 ids here, so wildcard match.
  */
-static struct pci_device_id gdthtable[] = {
+static struct pci_device_id gdthtable[] __devinitdata = {
     {PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID},
     {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID}, 
     {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC_XSCALE,PCI_ANY_ID,PCI_ANY_ID}, 
@@ -890,17 +832,12 @@
                                            ushort vendor, ushort device))
 {
     ulong base0, base1, base2;
-#if LINUX_VERSION_CODE >= 0x2015C
     struct pci_dev *pdev;
-#else
-    int error;
-    ushort idx;
-#endif
     
     TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n",
           *cnt, vendor, device));
 
-#if LINUX_VERSION_CODE >= 0x20363
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     pdev = NULL;
     while ((pdev = pci_find_device(vendor, device, pdev)) 
            != NULL) {
@@ -938,7 +875,7 @@
                 pcistr[*cnt].irq, pcistr[*cnt].dpmem));
         (*cnt)++;
     }       
-#elif LINUX_VERSION_CODE >= 0x2015C
+#else
     pdev = NULL;
     while ((pdev = pci_find_device(vendor, device, pdev)) 
            != NULL) {
@@ -979,66 +916,6 @@
                 pcistr[*cnt].irq, pcistr[*cnt].dpmem));
         (*cnt)++;
     }       
-#else   
-    idx = 0;
-    while (!pcibios_find_device(vendor, device, idx++,
-                                &pcistr[*cnt].bus,&pcistr[*cnt].device_fn)) {
-        if (*cnt >= MAXHA)
-            return;
-        /* GDT PCI ctr. found, now read resources from config space */
-#if LINUX_VERSION_CODE >= 0x010300
-#define GDTH_BASEP      (int *)
-#else
-#define GDTH_BASEP
-#endif
-        if ((error = pcibios_read_config_dword(pcistr[*cnt].bus,
-                                               pcistr[*cnt].device_fn,
-                                               PCI_BASE_ADDRESS_0,
-                                               GDTH_BASEP&base0)) ||
-            (error = pcibios_read_config_dword(pcistr[*cnt].bus,
-                                               pcistr[*cnt].device_fn,
-                                               PCI_BASE_ADDRESS_1,
-                                               GDTH_BASEP&base1)) ||
-            (error = pcibios_read_config_dword(pcistr[*cnt].bus,
-                                               pcistr[*cnt].device_fn,
-                                               PCI_BASE_ADDRESS_2,
-                                               GDTH_BASEP&base2)) ||
-            (error = pcibios_read_config_word(pcistr[*cnt].bus,
-                                              pcistr[*cnt].device_fn,
-                                              PCI_SUBSYSTEM_ID,
-                                              &pcistr[*cnt].subdevice_id)) ||
-            (error = pcibios_read_config_byte(pcistr[*cnt].bus,
-                                              pcistr[*cnt].device_fn,
-                                              PCI_INTERRUPT_LINE,
-                                              &pcistr[*cnt].irq))) {
-            printk("GDT-PCI: error %d reading configuration space", error);
-            continue;
-        }
-        pcistr[*cnt].vendor_id = vendor;
-        pcistr[*cnt].device_id = device;
-        if (device <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
-            device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
-            if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
-                PCI_BASE_ADDRESS_SPACE_MEMORY)
-                continue;
-            pcistr[*cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
-        } else {                                    /* GDT6110, GDT6120, .. */
-            if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
-                PCI_BASE_ADDRESS_SPACE_MEMORY ||
-                (base2 & PCI_BASE_ADDRESS_SPACE) !=
-                PCI_BASE_ADDRESS_SPACE_MEMORY ||
-                (base1 & PCI_BASE_ADDRESS_SPACE) !=
-                PCI_BASE_ADDRESS_SPACE_IO)
-                continue;
-            pcistr[*cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
-            pcistr[*cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
-            pcistr[*cnt].io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
-        }
-        TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
-                pcistr[*cnt].bus, PCI_SLOT(pcistr[*cnt].device_fn), 
-                pcistr[*cnt].irq, pcistr[*cnt].dpmem));
-        (*cnt)++;
-    }
 #endif
 }   
 
@@ -1168,6 +1045,8 @@
         ha->type = GDT_EISA;
         ha->stype = id;
     }
+
+    ha->dma64_support = 0;
     return 1;
 }
 
@@ -1181,7 +1060,7 @@
 
     TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr));
 
-    ha->brd = gdth_mmap(bios_adr, sizeof(gdt2_dpram_str));
+    ha->brd = ioremap(bios_adr, sizeof(gdt2_dpram_str));
     if (ha->brd == NULL) {
         printk("GDT-ISA: Initialization error (DPMEM remap error)\n");
         return 0;
@@ -1191,8 +1070,8 @@
     /* reset interface area */
     memset_io((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u));
     if (gdth_readl(&dp2_ptr->u) != 0) {
-        printk("GDT-PCI: Initialization error (DPMEM write error)\n");
-        gdth_munmap(ha->brd);
+        printk("GDT-ISA: Initialization error (DPMEM write error)\n");
+        iounmap(ha->brd);
         return 0;
     }
 
@@ -1227,7 +1106,7 @@
     while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
         if (--retries == 0) {
             printk("GDT-ISA: Initialization error (DEINIT failed)\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         gdth_delay(1);
@@ -1237,7 +1116,7 @@
     gdth_writeb(0xff, &dp2_ptr->io.irqdel);
     if (prot_ver != PROTOCOL_VERSION) {
         printk("GDT-ISA: Illegal protocol version\n");
-        gdth_munmap(ha->brd);
+        iounmap(ha->brd);
         return 0;
     }
 
@@ -1259,13 +1138,15 @@
     while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
         if (--retries == 0) {
             printk("GDT-ISA: Initialization error\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         gdth_delay(1);
     }
     gdth_writeb(0, &dp2_ptr->u.ic.Status);
     gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+
+    ha->dma64_support = 0;
     return 1;
 }
 
@@ -1279,9 +1160,6 @@
     unchar prot_ver;
     ushort command;
     int i, found = FALSE;
-#if LINUX_VERSION_CODE < 0x2015C
-    int rom_addr;
-#endif
 
     TRACE(("gdth_init_pci()\n"));
 
@@ -1293,13 +1171,13 @@
     ha->stype = (ulong32)pcistr->device_id;
     ha->subdevice_id = pcistr->subdevice_id;
     ha->irq = pcistr->irq;
-#if LINUX_VERSION_CODE >= 0x20400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     ha->pdev = pcistr->pdev;
 #endif
     
     if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) {  /* GDT6000/B */
         TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
-        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6_dpram_str));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str));
         if (ha->brd == NULL) {
             printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
             return 0;
@@ -1312,8 +1190,8 @@
                    pcistr->dpmem);
             found = FALSE;
             for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
-                gdth_munmap(ha->brd);
-                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1322,15 +1200,10 @@
                     TRACE2(("init_pci_old() address 0x%x busy\n", i));
                     continue;
                 }
-                gdth_munmap(ha->brd);
-#if LINUX_VERSION_CODE >= 0x2015C
+                iounmap(ha->brd);
                 pci_write_config_dword(pcistr->pdev, 
                                        PCI_BASE_ADDRESS_0, i);
-#else
-                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                           PCI_BASE_ADDRESS_0, i);
-#endif
-                ha->brd = gdth_mmap(i, sizeof(gdt6_dpram_str)); 
+                ha->brd = ioremap(i, sizeof(gdt6_dpram_str)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1345,14 +1218,14 @@
             }   
             if (!found) {
                 printk("GDT-PCI: No free address found!\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
         }
         memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
         if (gdth_readl(&dp6_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         
@@ -1370,7 +1243,7 @@
         while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
@@ -1380,7 +1253,7 @@
         gdth_writeb(0xff, &dp6_ptr->io.irqdel);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
 
@@ -1390,7 +1263,7 @@
         /* special command to controller BIOS */
         gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
         gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x01, &dp6_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
         gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
         gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
         gdth_writeb(0, &dp6_ptr->io.event);
@@ -1399,7 +1272,7 @@
         while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
@@ -1407,14 +1280,16 @@
         gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
         gdth_writeb(0xff, &dp6_ptr->io.irqdel);
 
+        ha->dma64_support = 0;
+
     } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */
         ha->plx = (gdt6c_plx_regs *)pcistr->io;
         TRACE2(("init_pci_new() dpmem %lx irq %d\n",
             pcistr->dpmem,ha->irq));
-        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6c_dpram_str));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6c_dpram_str));
         if (ha->brd == NULL) {
             printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         /* check and reset interface area */
@@ -1425,8 +1300,8 @@
                    pcistr->dpmem);
             found = FALSE;
             for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
-                gdth_munmap(ha->brd);
-                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1435,15 +1310,10 @@
                     TRACE2(("init_pci_plx() address 0x%x busy\n", i));
                     continue;
                 }
-                gdth_munmap(ha->brd);
-#if LINUX_VERSION_CODE >= 0x2015C
+                iounmap(ha->brd);
                 pci_write_config_dword(pcistr->pdev, 
                                        PCI_BASE_ADDRESS_2, i);
-#else
-                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                           PCI_BASE_ADDRESS_2, i);
-#endif
-                ha->brd = gdth_mmap(i, sizeof(gdt6c_dpram_str)); 
+                ha->brd = ioremap(i, sizeof(gdt6c_dpram_str)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1458,14 +1328,14 @@
             }   
             if (!found) {
                 printk("GDT-PCI: No free address found!\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
         }
         memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
         if (gdth_readl(&dp6c_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         
@@ -1486,7 +1356,7 @@
         while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
@@ -1495,7 +1365,7 @@
         gdth_writeb(0, &dp6c_ptr->u.ic.Status);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
 
@@ -1505,7 +1375,7 @@
         /* special command to controller BIOS */
         gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
         gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x01, &dp6c_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
         gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
         gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
         
@@ -1516,23 +1386,25 @@
         while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
         }
         gdth_writeb(0, &dp6c_ptr->u.ic.S_Status);
 
+        ha->dma64_support = 0;
+
     } else {                                            /* MPR */
         TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
-        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6m_dpram_str));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6m_dpram_str));
         if (ha->brd == NULL) {
             printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
             return 0;
         }
 
         /* manipulate config. space to enable DPMEM, start RP controller */
-#if LINUX_VERSION_CODE >= 0x20363
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
         pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
         command |= 6;
         pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
@@ -1543,7 +1415,7 @@
         gdth_delay(1);
         pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
                                pci_resource_start(pcistr->pdev, 8));
-#elif LINUX_VERSION_CODE >= 0x2015C
+#else
         pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
         command |= 6;
         pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
@@ -1554,22 +1426,6 @@
         gdth_delay(1);
         pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
                                pcistr->pdev->rom_address);
-#else
-        pcibios_read_config_word(pcistr->bus, pcistr->device_fn,
-                                 PCI_COMMAND, &command);
-        command |= 6;
-        pcibios_write_config_word(pcistr->bus, pcistr->device_fn, 
-                                  PCI_COMMAND, command);
-        pcibios_read_config_dword(pcistr->bus, pcistr->device_fn,
-                                  PCI_ROM_ADDRESS, &rom_addr);
-        if (rom_addr == 1UL)
-            rom_addr = 0UL;
-        i = 0xFEFF0001UL;
-        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                   PCI_ROM_ADDRESS, i);
-        gdth_delay(1);
-        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                   PCI_ROM_ADDRESS, rom_addr);
 #endif
         
         /* Ensure that it is safe to access the non HW portions of DPMEM.
@@ -1585,8 +1441,8 @@
                    pcistr->dpmem);
             found = FALSE;
             for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
-                gdth_munmap(ha->brd);
-                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1595,15 +1451,10 @@
                     TRACE2(("init_pci_mpr() address 0x%x busy\n", i));
                     continue;
                 }
-                gdth_munmap(ha->brd);
-#if LINUX_VERSION_CODE >= 0x2015C
+                iounmap(ha->brd);
                 pci_write_config_dword(pcistr->pdev, 
                                        PCI_BASE_ADDRESS_0, i);
-#else
-                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                           PCI_BASE_ADDRESS_0, i);
-#endif
-                ha->brd = gdth_mmap(i, sizeof(gdt6m_dpram_str)); 
+                ha->brd = ioremap(i, sizeof(gdt6m_dpram_str)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1618,7 +1469,7 @@
             }   
             if (!found) {
                 printk("GDT-PCI: No free address found!\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
         }
@@ -1639,7 +1490,7 @@
         while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
@@ -1648,7 +1499,7 @@
         gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
 
@@ -1658,7 +1509,7 @@
         /* special command to controller BIOS */
         gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
         gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x01, &dp6m_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
         gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
         gdth_writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
         gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
@@ -1667,12 +1518,32 @@
         while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+
+        /* read FW version to detect 64-bit DMA support */
+        gdth_writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
         }
+        prot_ver = (unchar)(gdth_readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
         gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+        if (prot_ver < 0x2b)      /* FW < x.43: no 64-bit DMA support */
+            ha->dma64_support = 0;
+        else 
+            ha->dma64_support = 1;
     }
 
     return 1;
@@ -1950,7 +1821,7 @@
 
 
 static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
-                             ulong32 p2,ulong32 p3)
+                             ulong64 p2,ulong64 p3)
 {
     register gdth_ha_str *ha;
     register gdth_cmd_str *cmd_ptr;
@@ -1976,23 +1847,35 @@
         if (service == CACHESERVICE) {
             if (opcode == GDT_IOCTL) {
                 cmd_ptr->u.ioctl.subfunc = p1;
-                cmd_ptr->u.ioctl.channel = p2;
+                cmd_ptr->u.ioctl.channel = (ulong32)p2;
                 cmd_ptr->u.ioctl.param_size = (ushort)p3;
                 cmd_ptr->u.ioctl.p_param = ha->scratch_phys;
             } else {
-                cmd_ptr->u.cache.DeviceNo = (ushort)p1;
-                cmd_ptr->u.cache.BlockNo  = p2;
+                if (ha->cache_feat & GDT_64BIT) {
+                    cmd_ptr->u.cache64.DeviceNo = (ushort)p1;
+                    cmd_ptr->u.cache64.BlockNo  = p2;
+                } else {
+                    cmd_ptr->u.cache.DeviceNo = (ushort)p1;
+                    cmd_ptr->u.cache.BlockNo  = (ulong32)p2;
+                }
             }
         } else if (service == SCSIRAWSERVICE) {
-            cmd_ptr->u.raw.direction  = p1;
-            cmd_ptr->u.raw.bus        = (unchar)p2;
-            cmd_ptr->u.raw.target     = (unchar)p3;
-            cmd_ptr->u.raw.lun        = (unchar)(p3 >> 8);
+            if (ha->raw_feat & GDT_64BIT) {
+                cmd_ptr->u.raw64.direction  = p1;
+                cmd_ptr->u.raw64.bus        = (unchar)p2;
+                cmd_ptr->u.raw64.target     = (unchar)p3;
+                cmd_ptr->u.raw64.lun        = (unchar)(p3 >> 8);
+            } else {
+                cmd_ptr->u.raw.direction  = p1;
+                cmd_ptr->u.raw.bus        = (unchar)p2;
+                cmd_ptr->u.raw.target     = (unchar)p3;
+                cmd_ptr->u.raw.lun        = (unchar)(p3 >> 8);
+            }
         } else if (service == SCREENSERVICE) {
             if (opcode == GDT_REALTIME) {
                 *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1;
-                *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = p2;
-                *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = p3;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = (ulong32)p2;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = (ulong32)p3;
             }
         }
         ha->cmd_len          = sizeof(gdth_cmd_str);
@@ -2020,6 +1903,7 @@
 {
     register gdth_ha_str *ha;
     ushort cdev_cnt, i;
+    int ok;
     ulong32 bus_no, drv_cnt, drv_no, j;
     gdth_getch_str *chn;
     gdth_drlist_str *drl;
@@ -2028,6 +1912,9 @@
     gdth_arcdl_str *alst;
     gdth_alist_str *alst2;
     gdth_oem_str_ioctl *oemstr;
+#ifdef INT_COAL
+    gdth_perf_modes *pmod;
+#endif
 
 #ifdef GDTH_RTC
     unchar rtc[12];
@@ -2036,11 +1923,20 @@
    
     TRACE(("gdth_search_drives() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
+    ok = 0;
 
     /* initialize controller services, at first: screen service */
-    if (!gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0)) {
-        printk("GDT: Initialization error screen service (code %d)\n",
-               ha->status);
+    ha->screen_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_X_INIT_SCR,0,0,0);
+        if (ok)
+            ha->screen_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error screen service (code %d)\n",
+               hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
@@ -2060,7 +1956,7 @@
         for (j = 0; j < 12; ++j) 
             rtc[j] = CMOS_READ(j);
     } while (rtc[0] != CMOS_READ(0));
-    spin_unlock_irqrestore(&rtc_lock, flags);
+    spin_lock_irqrestore(&rtc_lock, flags);
     TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
             *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
     /* 3. send to controller firmware */
@@ -2072,15 +1968,52 @@
     gdth_internal_cmd(hanum,CACHESERVICE,GDT_UNFREEZE_IO,0,0,0);
  
     /* initialize cache service */
-    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
-        printk("GDT: Initialization error cache service (code %d)\n",
-               ha->status);
+    ha->cache_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INIT_HOST,LINUX_OS,0,0);
+        if (ok)
+            ha->cache_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error cache service (code %d)\n",
+               hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
     cdev_cnt = (ushort)ha->info;
     ha->fw_vers = ha->service;
 
+#ifdef INT_COAL
+    if (ha->type == GDT_PCIMPR) {
+        /* set perf. modes */
+        pmod = (gdth_perf_modes *)ha->pscratch;
+        pmod->version          = 1;
+        pmod->st_mode          = 1;    /* enable one status buffer */
+        *((ulong64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys;
+        pmod->st_buff_indx1    = COALINDEX;
+        pmod->st_buff_addr2    = 0;
+        pmod->st_buff_u_addr2  = 0;
+        pmod->st_buff_indx2    = 0;
+        pmod->st_buff_size     = sizeof(gdth_coal_status) * MAXOFFSETS;
+        pmod->cmd_mode         = 0;    // disable all cmd buffers
+        pmod->cmd_buff_addr1   = 0;
+        pmod->cmd_buff_u_addr1 = 0;
+        pmod->cmd_buff_indx1   = 0;
+        pmod->cmd_buff_addr2   = 0;
+        pmod->cmd_buff_u_addr2 = 0;
+        pmod->cmd_buff_indx2   = 0;
+        pmod->cmd_buff_size    = 0;
+        pmod->reserved1        = 0;            
+        pmod->reserved2        = 0;            
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,SET_PERF_MODES,
+                              INVALID_CHANNEL,sizeof(gdth_perf_modes))) {
+            printk("GDT-HA %d: Interrupt coalescing activated\n", hanum);
+        }
+    }
+#endif
+
     /* detect number of buses - try new IOCTL */
     iocr = (gdth_raw_iochan_str *)ha->pscratch;
     iocr->hdr.version        = 0xffffffff;
@@ -2108,8 +2041,8 @@
                                    IO_CHANNEL | INVALID_CHANNEL,
                                    sizeof(gdth_getch_str))) {
                 if (bus_no == 0) {
-                    printk("GDT: Error detecting channel count (0x%x)\n",
-                           ha->status);
+                    printk("GDT-HA %d: Error detecting channel count (0x%x)\n",
+                           hanum, ha->status);
                     return 0;
                 }
                 break;
@@ -2126,8 +2059,8 @@
     /* read cache configuration */
     if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
                            INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
-        printk("GDT: Initialization error cache service (code %d)\n",
-               ha->status);
+        printk("GDT-HA %d: Initialization error cache service (code %d)\n",
+               hanum, ha->status);
         return 0;
     }
     ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar;
@@ -2246,9 +2179,17 @@
     }       
                                   
     /* initialize raw service */
-    if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) {
-        printk("GDT: Initialization error raw service (code %d)\n",
-               ha->status);
+    ha->raw_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_X_INIT_RAW,0,0,0);
+        if (ok)
+            ha->raw_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error raw service (code %d)\n",
+               hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
@@ -2260,7 +2201,7 @@
         if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) {
             TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n",
                     ha->info));
-            ha->raw_feat = (ushort)ha->info;
+            ha->raw_feat |= (ushort)ha->info;
         }
     } 
 
@@ -2271,7 +2212,7 @@
         if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
             TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n",
                     ha->info));
-            ha->cache_feat = (ushort)ha->info;
+            ha->cache_feat |= (ushort)ha->info;
         }
     }
 
@@ -2291,8 +2232,8 @@
             if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0,
                                    reserve_list[i+1], reserve_list[i+2] | 
                                    (reserve_list[i+3] << 8))) {
-                printk("GDT: Error raw service (RESERVE, code %d)\n",
-                       ha->status);
+                printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n",
+                       hanum, ha->status);
              }
         }
     }
@@ -2305,17 +2246,32 @@
                           CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL,
                           sizeof(gdth_oem_str_ioctl))) {
         TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n"));
-        printk("GDT CTR%d Vendor: %s\n",hanum,oemstr->text.oem_company_name);
+        printk("GDT-HA %d: Vendor: %s Name: %s\n",
+               hanum,oemstr->text.oem_company_name,ha->binfo.type_string);
         /* Save the Host Drive inquiry data */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,
-		sizeof(ha->oem_name));
+                sizeof(ha->oem_name));
+#else
+        strncpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,7);
+        ha->oem_name[7] = '\0';
+#endif
     } else {
         /* Old method, based on PCI ID */
         TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n"));
+        printk("GDT-HA %d: Name: %s\n",
+               hanum,ha->binfo.type_string);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         if (ha->oem_id == OEM_ID_INTEL)
             strlcpy(ha->oem_name,"Intel  ", sizeof(ha->oem_name));
         else
             strlcpy(ha->oem_name,"ICP    ", sizeof(ha->oem_name));
+#else 
+        if (ha->oem_id == OEM_ID_INTEL)
+            strcpy(ha->oem_name,"Intel  ");
+        else
+            strcpy(ha->oem_name,"ICP    ");
+#endif
     }
 
     /* scanning for host drives */
@@ -2329,7 +2285,8 @@
 static int gdth_analyse_hdrive(int hanum,ushort hdrive)
 {
     register gdth_ha_str *ha;
-    int drv_cyls, drv_hds, drv_secs;
+    ulong32 drv_cyls;
+    int drv_hds, drv_secs;
 
     TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive));
     if (hdrive >= MAX_HDRIVES)
@@ -2340,7 +2297,7 @@
         return 0;
     ha->hdr[hdrive].present = TRUE;
     ha->hdr[hdrive].size = ha->info;
-
+   
     /* evaluate mapping (sectors per head, heads per cylinder) */
     ha->hdr[hdrive].size &= ~SECS32;
     if (ha->info2 == 0) {
@@ -2348,15 +2305,22 @@
     } else {
         drv_hds = ha->info2 & 0xff;
         drv_secs = (ha->info2 >> 8) & 0xff;
-        drv_cyls = ha->hdr[hdrive].size /drv_hds/drv_secs;
+        drv_cyls = (ulong32)ha->hdr[hdrive].size / drv_hds / drv_secs;
     }
     ha->hdr[hdrive].heads = (unchar)drv_hds;
     ha->hdr[hdrive].secs  = (unchar)drv_secs;
     /* round size */
     ha->hdr[hdrive].size  = drv_cyls * drv_hds * drv_secs;
+    
+    if (ha->cache_feat & GDT_64BIT) {
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INFO,hdrive,0,0)
+            && ha->info2 != 0) {
+            ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info;
+        }
+    }
     TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n",
             hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs));
-            
+
     /* get informations about device */
     if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) {
         TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
@@ -2398,14 +2362,13 @@
     GDTH_LOCK_HA(ha, flags);
 
     scp->SCp.this_residual = (int)priority;
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
     t = scp->device->id;
 #else
     b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
     t = scp->target;
 #endif
-#if LINUX_VERSION_CODE >= 0x010300
     if (priority >= DEFAULT_PRI) {
         if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
             (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) {
@@ -2413,7 +2376,6 @@
             scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
         }
     }
-#endif
 
     if (ha->req_first==NULL) {
         ha->req_first = scp;                    /* queue was empty */
@@ -2465,7 +2427,7 @@
     for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
         if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
             pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         b = virt_ctr ? NUMDATA(nscp->device->host)->busnum : nscp->device->channel;
         t = nscp->device->id;
         l = nscp->device->lun;
@@ -2493,10 +2455,7 @@
             firsttime = FALSE;
         }
 
-#if LINUX_VERSION_CODE >= 0x010300
-        if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) 
-#endif
-        {
+        if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) {        
         if (nscp->SCp.phase == -1) {
             nscp->SCp.phase = CACHESERVICE;           /* default: cache svc. */ 
             if (nscp->cmnd[0] == TEST_UNIT_READY) {
@@ -2565,16 +2524,11 @@
                         GDTH_LOCK_HA(ha,flags);
                 }
             }
-        } else
-
-#if LINUX_VERSION_CODE >= 0x010300
-        if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) {
+        } else if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) {
             if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
                 this_cmd = FALSE;
             next_cmd = FALSE;
-        } else
-#endif
-        if (b != ha->virt_bus) {
+        } else if (b != ha->virt_bus) {
             if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW ||
                 !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) 
                 this_cmd = FALSE;
@@ -2603,6 +2557,9 @@
               case VERIFY:
               case START_STOP:
               case MODE_SENSE:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+              case SERVICE_ACTION_IN:
+#endif
                 TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
                        nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
                        nscp->cmnd[4],nscp->cmnd[5]));
@@ -2674,6 +2631,10 @@
               case WRITE_6:
               case READ_10:
               case WRITE_10:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+              case READ_16:
+              case WRITE_16:
+#endif
                 if (ha->hdr[t].media_changed) {
                     /* return UNIT_ATTENTION */
                     TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
@@ -2701,8 +2662,8 @@
                 TRACE2(("cache cmd %x/%x/%x/%x/%x/%x unknown\n",nscp->cmnd[0],
                         nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
                         nscp->cmnd[4],nscp->cmnd[5]));
-                printk("GDT: Unknown SCSI command 0x%x to cache service !\n",
-                       nscp->cmnd[0]);
+                printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n",
+                       hanum, nscp->cmnd[0]);
                 nscp->result = DID_ABORT << 16;
                 if (!nscp->SCp.have_data_in)
                     nscp->SCp.have_data_in++;
@@ -2737,11 +2698,11 @@
 
     if (gdth_polling && ha->cmd_cnt > 0) {
         if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
-            printk("GDT: Controller %d: Command %d timed out !\n",
+            printk("GDT-HA %d: Command %d timed out !\n",
                    hanum,cmd_index);
     }
 }
-    
+   
 static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
                                     char *buffer,ushort count)
 {
@@ -2757,7 +2718,7 @@
 
     if (scp->use_sg) {
         sl = (struct scatterlist *)scp->request_buffer;
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
         sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,PCI_DMA_FROMDEVICE);
         for (i=0,cpsum=0; i<sgcnt; ++i,++sl) {
             cpnow = (ushort)sg_dma_len(sl);
@@ -2766,7 +2727,12 @@
             if (cpsum+cpnow > cpcount) 
                 cpnow = cpcount - cpsum;
             cpsum += cpnow;
-            address = (char *)phys_to_virt(sg_dma_address(sl));
+            if (!sl->page) {
+                printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n",
+                       hanum);
+                return;
+            }
+            address = (char *)(page_address(sl->page) + sl->offset);
             memcpy(address,buffer,cpnow);
             if (cpsum == cpcount)
                 break;
@@ -2806,7 +2772,7 @@
     gdth_modep_data mpd;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     t  = scp->device->id;
 #else
     t  = scp->target;
@@ -2814,6 +2780,9 @@
     TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
            scp->cmnd[0],t));
 
+    scp->result = DID_OK << 16;
+    scp->sense_buffer[0] = 0;
+
     switch (scp->cmnd[0]) {
       case TEST_UNIT_READY:
       case VERIFY:
@@ -2864,19 +2833,35 @@
 
       case READ_CAPACITY:
         TRACE2(("Read capacity hdrive %d\n",t));
-        rdc.last_block_no = ntohl(ha->hdr[t].size-1);
-        rdc.block_length  = ntohl(SECTOR_SIZE);
+        if (ha->hdr[t].size > (ulong64)0xffffffff)
+            rdc.last_block_no = 0xffffffff;
+        else
+            rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
+        rdc.block_length  = cpu_to_be32(SECTOR_SIZE);
         gdth_copy_internal_data(hanum,scp,(char*)&rdc,sizeof(gdth_rdcap_data));
         break;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+      case SERVICE_ACTION_IN:
+        if ((scp->cmnd[1] & 0x1f) == SAI_READ_CAPACITY_16 &&
+            (ha->cache_feat & GDT_64BIT)) {
+            gdth_rdcap16_data rdc16;
+
+            TRACE2(("Read capacity (16) hdrive %d\n",t));
+            rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1);
+            rdc16.block_length  = cpu_to_be32(SECTOR_SIZE);
+            gdth_copy_internal_data(hanum,scp,(char*)&rdc16,sizeof(gdth_rdcap16_data));
+        } else { 
+            scp->result = DID_ABORT << 16;
+        }
+        break;
+#endif
+
       default:
         TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
         break;
     }
 
-    scp->result = DID_OK << 16;
-    scp->sense_buffer[0] = 0;
-
     if (!scp->SCp.have_data_in)
         scp->SCp.have_data_in++;
     else 
@@ -2890,9 +2875,14 @@
     register gdth_ha_str *ha;
     register gdth_cmd_str *cmdp;
     struct scatterlist *sl;
-    ushort i, cnt;
-    ulong32 no, phys_addr;
-    int cmd_index, read_write, sgcnt;
+    ulong32 cnt, blockcnt;
+    ulong64 no, blockno;
+    dma_addr_t phys_addr;
+    int i, cmd_index, read_write, sgcnt, mode64;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+    struct page *page;
+    ulong offset;
+#endif
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
@@ -2902,6 +2892,11 @@
     if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
         return 0;
 
+    mode64 = (ha->cache_feat & GDT_64BIT) ? TRUE : FALSE;
+    /* test for READ_16, WRITE_16 if !mode64 ? ---
+       not required, should not occur due to error return on 
+       READ_CAPACITY_16 */
+
     cmdp->Service = CACHESERVICE;
     cmdp->RequestBuffer = scp;
     /* search free command index */
@@ -2929,7 +2924,11 @@
         else
             cmdp->OpCode = GDT_FLUSH;
     } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10 ||
-               scp->cmnd[0] == WRITE_12) {
+               scp->cmnd[0] == WRITE_12 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+               || scp->cmnd[0] == WRITE_16
+#endif
+    ) {
         read_write = 1;
         if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && 
                                    (ha->cache_feat & GDT_WR_THROUGH)))
@@ -2940,86 +2939,157 @@
         read_write = 2;
         cmdp->OpCode = GDT_READ;
     }
-    
-    cmdp->BoardNode        = LOCALBOARD;
-    cmdp->u.cache.DeviceNo = hdrive;
-    cmdp->u.cache.BlockNo  = 1;
-    cmdp->u.cache.sg_canz  = 0;
+
+    cmdp->BoardNode = LOCALBOARD;
+    if (mode64) {
+        cmdp->u.cache64.DeviceNo = hdrive;
+        cmdp->u.cache64.BlockNo  = 1;
+        cmdp->u.cache64.sg_canz  = 0;
+    } else {
+        cmdp->u.cache.DeviceNo = hdrive;
+        cmdp->u.cache.BlockNo  = 1;
+        cmdp->u.cache.sg_canz  = 0;
+    }
 
     if (read_write) {
-        if (scp->cmd_len != 6) {
+        if (scp->cmd_len == 16) {
+            memcpy(&no, &scp->cmnd[2], sizeof(ulong64));
+            blockno = be64_to_cpu(no);
+            memcpy(&cnt, &scp->cmnd[10], sizeof(ulong32));
+            blockcnt = be32_to_cpu(cnt);
+        } else if (scp->cmd_len == 10) {
             memcpy(&no, &scp->cmnd[2], sizeof(ulong32));
-            cmdp->u.cache.BlockNo = ntohl(no);
+            blockno = be32_to_cpu(no);
             memcpy(&cnt, &scp->cmnd[7], sizeof(ushort));
-            cmdp->u.cache.BlockCnt = (ulong32)ntohs(cnt);
+            blockcnt = be16_to_cpu(cnt);
         } else {
             memcpy(&no, &scp->cmnd[0], sizeof(ulong32));
-            cmdp->u.cache.BlockNo = ntohl(no) & 0x001fffffUL;
-            cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
+            blockno = be32_to_cpu(no) & 0x001fffffUL;
+            blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
+        }
+        if (mode64) {
+            cmdp->u.cache64.BlockNo = blockno;
+            cmdp->u.cache64.BlockCnt = blockcnt;
+        } else {
+            cmdp->u.cache.BlockNo = (ulong32)blockno;
+            cmdp->u.cache.BlockCnt = blockcnt;
         }
 
         if (scp->use_sg) {
-            cmdp->u.cache.DestAddr= 0xffffffff;
             sl = (struct scatterlist *)scp->request_buffer;
             sgcnt = scp->use_sg;
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
             scp->SCp.Status = GDTH_MAP_SG;
             scp->SCp.Message = (read_write == 1 ? 
                 PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);   
             sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
-            for (i=0; i<sgcnt; ++i,++sl) {
-                cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl);
-                cmdp->u.cache.sg_lst[i].sg_len = sg_dma_len(sl);
+            if (mode64) {
+                cmdp->u.cache64.DestAddr= (ulong64)-1;
+                cmdp->u.cache64.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
+                        ha->dma64_cnt++;
+                    else
+                        ha->dma32_cnt++;
+#endif
+                    cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            } else {
+                cmdp->u.cache.DestAddr= 0xffffffff;
+                cmdp->u.cache.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    ha->dma32_cnt++;
+#endif
+                    cmdp->u.cache.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
             }
 #else
-            for (i=0; i<sgcnt; ++i,++sl) {
-                cmdp->u.cache.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
-                cmdp->u.cache.sg_lst[i].sg_len = (ulong32)sl->length;
+            if (mode64) {
+                cmdp->u.cache64.DestAddr= (ulong64)-1;
+                cmdp->u.cache64.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache64.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
+                    cmdp->u.cache64.sg_lst[i].sg_len = (ulong32)sl->length;
+                }
+            } else {
+                cmdp->u.cache.DestAddr= 0xffffffff;
+                cmdp->u.cache.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
+                    cmdp->u.cache.sg_lst[i].sg_len = (ulong32)sl->length;
+                }
             }
 #endif
-            cmdp->u.cache.sg_canz = (ulong32)i;
 
 #ifdef GDTH_STATISTICS
-            if (max_sg < (ulong32)i) {
-                max_sg = (ulong32)i;
-                TRACE3(("GDT: max_sg = %d\n",i));
+            if (max_sg < (ulong32)sgcnt) {
+                max_sg = (ulong32)sgcnt;
+                TRACE3(("GDT: max_sg = %d\n",max_sg));
             }
 #endif
-            if (i<GDTH_MAXSG)
-                cmdp->u.cache.sg_lst[i].sg_len = 0;
+
         } else {
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
             scp->SCp.Status = GDTH_MAP_SINGLE;
             scp->SCp.Message = (read_write == 1 ? 
-                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);   
-            phys_addr = pci_map_single(ha->pdev,scp->request_buffer,
-                                       scp->request_bufflen,scp->SCp.Message);
+                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+            page = virt_to_page(scp->request_buffer);
+            offset = (ulong)scp->request_buffer & ~PAGE_MASK;
+            phys_addr = pci_map_page(ha->pdev,page,offset,
+                                     scp->request_bufflen,scp->SCp.Message);
             scp->SCp.dma_handle = phys_addr;
 #else
             phys_addr = virt_to_bus(scp->request_buffer);
 #endif
-            if (ha->cache_feat & SCATTER_GATHER) {
-                cmdp->u.cache.DestAddr = 0xffffffff;
-                cmdp->u.cache.sg_canz = 1;
-                cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr;
-                cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
-                cmdp->u.cache.sg_lst[1].sg_len = 0;
+            if (mode64) {
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    cmdp->u.cache64.DestAddr = (ulong64)-1;
+                    cmdp->u.cache64.sg_canz = 1;
+                    cmdp->u.cache64.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.cache64.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.cache64.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.cache64.DestAddr  = phys_addr;
+                    cmdp->u.cache64.sg_canz= 0;
+                }
             } else {
-                cmdp->u.cache.DestAddr  = phys_addr;
-                cmdp->u.cache.sg_canz= 0;
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    cmdp->u.cache.DestAddr = 0xffffffff;
+                    cmdp->u.cache.sg_canz = 1;
+                    cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.cache.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.cache.DestAddr  = phys_addr;
+                    cmdp->u.cache.sg_canz= 0;
+                }
             }
         }
     }
-    TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
-           cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
-           cmdp->u.cache.sg_lst[0].sg_ptr,
-           cmdp->u.cache.sg_lst[0].sg_len));
-    TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
-           cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
-
     /* evaluate command size, check space */
-    ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
-        (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
+    if (mode64) {
+        TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+               cmdp->u.cache64.DestAddr,cmdp->u.cache64.sg_canz,
+               cmdp->u.cache64.sg_lst[0].sg_ptr,
+               cmdp->u.cache64.sg_lst[0].sg_len));
+        TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
+               cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) +
+            (ushort)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str);
+    } else {
+        TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+               cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
+               cmdp->u.cache.sg_lst[0].sg_ptr,
+               cmdp->u.cache.sg_lst[0].sg_len));
+        TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
+               cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
+            (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
+    }
     if (ha->cmd_len & 3)
         ha->cmd_len += (4 - (ha->cmd_len & 3));
 
@@ -3043,12 +3113,16 @@
     register gdth_cmd_str *cmdp;
     struct scatterlist *sl;
     ushort i;
-    ulong32 phys_addr, sense_paddr;
-    int cmd_index, sgcnt;
+    dma_addr_t phys_addr, sense_paddr;
+    int cmd_index, sgcnt, mode64;
     unchar t,l;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+    struct page *page;
+    ulong offset;
+#endif
 
     ha = HADATA(gdth_ctr_tab[hanum]);
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     t = scp->device->id;
     l = scp->device->lun;
 #else
@@ -3062,6 +3136,8 @@
     if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
         return 0;
 
+    mode64 = (ha->raw_feat & GDT_64BIT) ? TRUE : FALSE;
+
     cmdp->Service = SCSIRAWSERVICE;
     cmdp->RequestBuffer = scp;
     /* search free command index */
@@ -3077,95 +3153,176 @@
     if (scp->SCp.sent_command != -1) {
         cmdp->OpCode           = scp->SCp.sent_command; /* special raw cmd. */
         cmdp->BoardNode        = LOCALBOARD;
-        cmdp->u.raw.direction  = (scp->SCp.phase >> 8);
-        TRACE2(("special raw cmd 0x%x param 0x%x\n", 
-                cmdp->OpCode, cmdp->u.raw.direction));
+        if (mode64) {
+            cmdp->u.raw64.direction = (scp->SCp.phase >> 8);
+            TRACE2(("special raw cmd 0x%x param 0x%x\n", 
+                    cmdp->OpCode, cmdp->u.raw64.direction));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst);
+        } else {
+            cmdp->u.raw.direction  = (scp->SCp.phase >> 8);
+            TRACE2(("special raw cmd 0x%x param 0x%x\n", 
+                    cmdp->OpCode, cmdp->u.raw.direction));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst);
+        }
 
-        /* evaluate command size */
-        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst);
     } else {
-#if LINUX_VERSION_CODE >= 0x020400
-        sense_paddr = pci_map_single(ha->pdev,scp->sense_buffer,
-                                     16,PCI_DMA_FROMDEVICE);
-        scp->SCp.buffer = (struct scatterlist *)sense_paddr;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+        page = virt_to_page(scp->sense_buffer);
+        offset = (ulong)scp->sense_buffer & ~PAGE_MASK;
+        sense_paddr = pci_map_page(ha->pdev,page,offset,
+                                   16,PCI_DMA_FROMDEVICE);
+        scp->SCp.buffer = (struct scatterlist *)((ulong32)sense_paddr);
+        /* high part, if 64bit */
+        scp->host_scribble = (char *)(ulong32)((ulong64)sense_paddr >> 32);
 #else
         sense_paddr = virt_to_bus(scp->sense_buffer);
 #endif
         cmdp->OpCode           = GDT_WRITE;             /* always */
         cmdp->BoardNode        = LOCALBOARD;
-        cmdp->u.raw.reserved   = 0;
-        cmdp->u.raw.mdisc_time = 0;
-        cmdp->u.raw.mcon_time  = 0;
-        cmdp->u.raw.clen       = scp->cmd_len;
-        cmdp->u.raw.target     = t;
-        cmdp->u.raw.lun        = l;
-        cmdp->u.raw.bus        = b;
-        cmdp->u.raw.priority   = 0;
-        cmdp->u.raw.link_p     = 0;
-        cmdp->u.raw.sdlen      = scp->request_bufflen;
-        cmdp->u.raw.sense_len  = 16;
-        cmdp->u.raw.sense_data = sense_paddr;
-        cmdp->u.raw.direction  = 
-            gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
-        memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
+        if (mode64) { 
+            cmdp->u.raw64.reserved   = 0;
+            cmdp->u.raw64.mdisc_time = 0;
+            cmdp->u.raw64.mcon_time  = 0;
+            cmdp->u.raw64.clen       = scp->cmd_len;
+            cmdp->u.raw64.target     = t;
+            cmdp->u.raw64.lun        = l;
+            cmdp->u.raw64.bus        = b;
+            cmdp->u.raw64.priority   = 0;
+            cmdp->u.raw64.sdlen      = scp->request_bufflen;
+            cmdp->u.raw64.sense_len  = 16;
+            cmdp->u.raw64.sense_data = sense_paddr;
+            cmdp->u.raw64.direction  = 
+                gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
+            memcpy(cmdp->u.raw64.cmd,scp->cmnd,16);
+        } else {
+            cmdp->u.raw.reserved   = 0;
+            cmdp->u.raw.mdisc_time = 0;
+            cmdp->u.raw.mcon_time  = 0;
+            cmdp->u.raw.clen       = scp->cmd_len;
+            cmdp->u.raw.target     = t;
+            cmdp->u.raw.lun        = l;
+            cmdp->u.raw.bus        = b;
+            cmdp->u.raw.priority   = 0;
+            cmdp->u.raw.link_p     = 0;
+            cmdp->u.raw.sdlen      = scp->request_bufflen;
+            cmdp->u.raw.sense_len  = 16;
+            cmdp->u.raw.sense_data = sense_paddr;
+            cmdp->u.raw.direction  = 
+                gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
+            memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
+        }
 
         if (scp->use_sg) {
-            cmdp->u.raw.sdata  = 0xffffffff;
             sl = (struct scatterlist *)scp->request_buffer;
             sgcnt = scp->use_sg;
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
             scp->SCp.Status = GDTH_MAP_SG;
             scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; 
             sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
-            for (i=0; i<sgcnt; ++i,++sl) {
-                cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl);
-                cmdp->u.raw.sg_lst[i].sg_len = sg_dma_len(sl);
+            if (mode64) {
+                cmdp->u.raw64.sdata = (ulong64)-1;
+                cmdp->u.raw64.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
+                        ha->dma64_cnt++;
+                    else
+                        ha->dma32_cnt++;
+#endif
+                    cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            } else {
+                cmdp->u.raw.sdata = 0xffffffff;
+                cmdp->u.raw.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    ha->dma32_cnt++;
+#endif
+                    cmdp->u.raw.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
             }
 #else
-            for (i=0; i<sgcnt; ++i,++sl) {
-                cmdp->u.raw.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
-                cmdp->u.raw.sg_lst[i].sg_len = (ulong32)sl->length;
+            if (mode64) {
+                cmdp->u.raw64.sdata = (ulong64)-1;
+                cmdp->u.raw64.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw64.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
+                    cmdp->u.raw64.sg_lst[i].sg_len = (ulong32)sl->length;
+                }
+            } else {
+                cmdp->u.raw.sdata = 0xffffffff;
+                cmdp->u.raw.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
+                    cmdp->u.raw.sg_lst[i].sg_len = (ulong32)sl->length;
+                }
             }
 #endif
-            cmdp->u.raw.sg_ranz = (ulong32)i;
 
 #ifdef GDTH_STATISTICS
-            if (max_sg < (ulong32)i) {
-                max_sg = (ulong32)i;
-                TRACE3(("GDT: max_sg = %d\n",i));
+            if (max_sg < sgcnt) {
+                max_sg = sgcnt;
+                TRACE3(("GDT: max_sg = %d\n",sgcnt));
             }
 #endif
-            if (i<GDTH_MAXSG)
-                cmdp->u.raw.sg_lst[i].sg_len = 0;
+
         } else {
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
             scp->SCp.Status = GDTH_MAP_SINGLE;
             scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; 
-            phys_addr = pci_map_single(ha->pdev,scp->request_buffer,
-                                       scp->request_bufflen,scp->SCp.Message);
+            page = virt_to_page(scp->request_buffer);
+            offset = (ulong)scp->request_buffer & ~PAGE_MASK;
+            phys_addr = pci_map_page(ha->pdev,page,offset,
+                                     scp->request_bufflen,scp->SCp.Message);
             scp->SCp.dma_handle = phys_addr;
 #else
             phys_addr = virt_to_bus(scp->request_buffer);
 #endif
-            if (ha->raw_feat & SCATTER_GATHER) {
-                cmdp->u.raw.sdata  = 0xffffffff;
-                cmdp->u.raw.sg_ranz= 1;
-                cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr;
-                cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
-                cmdp->u.raw.sg_lst[1].sg_len = 0;
+            if (mode64) {
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    cmdp->u.raw64.sdata  = (ulong64)-1;
+                    cmdp->u.raw64.sg_ranz= 1;
+                    cmdp->u.raw64.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.raw64.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.raw64.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.raw64.sdata  = phys_addr;
+                    cmdp->u.raw64.sg_ranz= 0;
+                }
             } else {
-                cmdp->u.raw.sdata  = phys_addr;
-                cmdp->u.raw.sg_ranz= 0;
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    cmdp->u.raw.sdata  = 0xffffffff;
+                    cmdp->u.raw.sg_ranz= 1;
+                    cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.raw.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.raw.sdata  = phys_addr;
+                    cmdp->u.raw.sg_ranz= 0;
+                }
             }
         }
-        TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
-               cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
-               cmdp->u.raw.sg_lst[0].sg_ptr,
-               cmdp->u.raw.sg_lst[0].sg_len));
-
-        /* evaluate command size */
-        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
-            (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
+        if (mode64) {
+            TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+                   cmdp->u.raw64.sdata,cmdp->u.raw64.sg_ranz,
+                   cmdp->u.raw64.sg_lst[0].sg_ptr,
+                   cmdp->u.raw64.sg_lst[0].sg_len));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) +
+                (ushort)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str);
+        } else {
+            TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+                   cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
+                   cmdp->u.raw.sg_lst[0].sg_ptr,
+                   cmdp->u.raw.sg_lst[0].sg_len));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
+                (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
+        }
     }
     /* check space */
     if (ha->cmd_len & 3)
@@ -3215,15 +3372,23 @@
     if (cmdp->OpCode == GDT_IOCTL) {
         TRACE2(("IOCTL\n"));
         ha->cmd_len = 
-            GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong32);
+            GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong64);
     } else if (cmdp->Service == CACHESERVICE) {
         TRACE2(("cache command %d\n",cmdp->OpCode));
-        ha->cmd_len = 
-            GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str);
+        if (ha->cache_feat & GDT_64BIT)
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + sizeof(gdth_sg64_str);
+        else
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str);
     } else if (cmdp->Service == SCSIRAWSERVICE) {
-        TRACE2(("raw command %d/%d\n",cmdp->OpCode,cmdp->u.raw.cmd[0]));
-        ha->cmd_len = 
-            GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str);
+        TRACE2(("raw command %d\n",cmdp->OpCode));
+        if (ha->raw_feat & GDT_64BIT)
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + sizeof(gdth_sg64_str);
+        else
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str);
     }
 
     if (ha->cmd_len & 3)
@@ -3366,10 +3531,14 @@
 
 /* SCSI interface functions */
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+#else
+static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+#endif
 {
     register gdth_ha_str *ha;
-    gdt6m_dpram_str *dp6m_ptr;
+    gdt6m_dpram_str *dp6m_ptr = NULL;
     gdt6_dpram_str *dp6_ptr;
     gdt2_dpram_str *dp2_ptr;
     Scsi_Cmnd *scp;
@@ -3377,13 +3546,23 @@
     unchar IStatus;
     ushort Service;
     ulong flags = 0;
+#ifdef INT_COAL
+    int coalesced = FALSE;
+    int next = FALSE;
+    gdth_coal_status *pcs = NULL;
+    int act_int_coal = 0;       
+#endif
 
     TRACE(("gdth_interrupt() IRQ %d\n",irq));
 
     /* if polling and not from gdth_wait() -> return */
     if (gdth_polling) {
         if (!gdth_from_wait) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
             return IRQ_HANDLED;
+#else
+            return;             
+#endif
         }
     }
 
@@ -3396,174 +3575,261 @@
         /* spurious interrupt */
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return IRQ_HANDLED;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
     }
+    ha = HADATA(gdth_ctr_tab[hanum]);
 
 #ifdef GDTH_STATISTICS
     ++act_ints;
 #endif
-    
-    ha = HADATA(gdth_ctr_tab[hanum]);
-    if (ha->type == GDT_EISA) {
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = inw(ha->bmic + MAILBOXREG+8);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else                                      /* no error */
-            ha->status = S_OK;
-        ha->info = inl(ha->bmic + MAILBOXREG+12);
-        ha->service = inw(ha->bmic + MAILBOXREG+10);
-        ha->info2 = inl(ha->bmic + MAILBOXREG+4);
-
-        outb(0xff, ha->bmic + EDOORREG);            /* acknowledge interrupt */
-        outb(0x00, ha->bmic + SEMA1REG);            /* reset status semaphore */
-    } else if (ha->type == GDT_ISA) {
-        dp2_ptr = (gdt2_dpram_str *)ha->brd;
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else                                      /* no error */
-            ha->status = S_OK;
-        ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
-        ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
-        ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
-
-        gdth_writeb(0xff, &dp2_ptr->io.irqdel);     /* acknowledge interrupt */
-        gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);   /* reset command index */
-        gdth_writeb(0, &dp2_ptr->io.Sema1);         /* reset status semaphore */
-    } else if (ha->type == GDT_PCI) {
-        dp6_ptr = (gdt6_dpram_str *)ha->brd;
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else                                      /* no error */
-            ha->status = S_OK;
-        ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
-        ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
-        ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
-
-        gdth_writeb(0xff, &dp6_ptr->io.irqdel);     /* acknowledge interrupt */
-        gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);   /* reset command index */
-        gdth_writeb(0, &dp6_ptr->io.Sema1);         /* reset status semaphore */
-    } else if (ha->type == GDT_PCINEW) {
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = inw(PTR2USHORT(&ha->plx->status));
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else
-            ha->status = S_OK;
-        ha->info = inl(PTR2USHORT(&ha->plx->info[0]));
-        ha->service = inw(PTR2USHORT(&ha->plx->service));
-        ha->info2 = inl(PTR2USHORT(&ha->plx->info[1]));
 
-        outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
-        outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
-    } else if (ha->type == GDT_PCIMPR) {
-        dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = gdth_readw(&dp6m_ptr->i960r.status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else                                      /* no error */
-            ha->status = S_OK;
-        ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
-        ha->service = gdth_readw(&dp6m_ptr->i960r.service);
-        ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+#ifdef INT_COAL
+    /* See if the fw is returning coalesced status */
+    if (IStatus == COALINDEX) {
+        /* Coalesced status.  Setup the initial status 
+           buffer pointer and flags */
+        pcs = ha->coal_stat;
+        coalesced = TRUE;        
+        next = TRUE;
+    }
 
-        /* event string */
-        if (IStatus == ASYNCINDEX) {
-            if (ha->service != SCREENSERVICE &&
-                (ha->fw_vers & 0xff) >= 0x1a) {
-                ha->dvr.severity =   
-                    gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.severity);
-                for (i = 0; i < 256; ++i) {
-                    ha->dvr.event_string[i] = gdth_readb
-                        (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]);
-                    if (ha->dvr.event_string[i] == 0)
-                        break;
-                }
-            }
+    do {
+        if (coalesced) {
+            /* For coalesced requests all status
+               information is found in the status buffer */
+            IStatus = (unchar)(pcs->status & 0xff);
+        }
+#endif
+    
+        if (ha->type == GDT_EISA) {
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = inw(ha->bmic + MAILBOXREG+8);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = inl(ha->bmic + MAILBOXREG+12);
+            ha->service = inw(ha->bmic + MAILBOXREG+10);
+            ha->info2 = inl(ha->bmic + MAILBOXREG+4);
+
+            outb(0xff, ha->bmic + EDOORREG);    /* acknowledge interrupt */
+            outb(0x00, ha->bmic + SEMA1REG);    /* reset status semaphore */
+        } else if (ha->type == GDT_ISA) {
+            dp2_ptr = (gdt2_dpram_str *)ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
+            ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
+            ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+
+            gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
+            gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
+            gdth_writeb(0, &dp2_ptr->io.Sema1);     /* reset status semaphore */
+        } else if (ha->type == GDT_PCI) {
+            dp6_ptr = (gdt6_dpram_str *)ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
+            ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
+            ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+
+            gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
+            gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
+            gdth_writeb(0, &dp6_ptr->io.Sema1);     /* reset status semaphore */
+        } else if (ha->type == GDT_PCINEW) {
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = inw(PTR2USHORT(&ha->plx->status));
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else
+                ha->status = S_OK;
+            ha->info = inl(PTR2USHORT(&ha->plx->info[0]));
+            ha->service = inw(PTR2USHORT(&ha->plx->service));
+            ha->info2 = inl(PTR2USHORT(&ha->plx->info[1]));
+
+            outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
+            outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
+        } else if (ha->type == GDT_PCIMPR) {
+            dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+#ifdef INT_COAL
+                if (coalesced)
+                    ha->status = pcs->ext_status && 0xffff;
+                else 
+#endif
+                    ha->status = gdth_readw(&dp6m_ptr->i960r.status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+#ifdef INT_COAL
+            /* get information */
+            if (coalesced) {    
+                ha->info = pcs->info0;
+                ha->info2 = pcs->info1;
+                ha->service = (pcs->ext_status >> 16) && 0xffff;
+            } else
+#endif
+            {
+                ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
+                ha->service = gdth_readw(&dp6m_ptr->i960r.service);
+                ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+            }
+            /* event string */
+            if (IStatus == ASYNCINDEX) {
+                if (ha->service != SCREENSERVICE &&
+                    (ha->fw_vers & 0xff) >= 0x1a) {
+                    ha->dvr.severity = gdth_readb
+                        (&((gdt6m_dpram_str *)ha->brd)->i960r.severity);
+                    for (i = 0; i < 256; ++i) {
+                        ha->dvr.event_string[i] = gdth_readb
+                            (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]);
+                        if (ha->dvr.event_string[i] == 0)
+                            break;
+                    }
+                }
+            }
+#ifdef INT_COAL
+            /* Make sure that non coalesced interrupts get cleared
+               before being handled by gdth_async_event/gdth_sync_event */
+            if (!coalesced)
+#endif                          
+            {
+                gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+                gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+            }
+        } else {
+            TRACE2(("gdth_interrupt() unknown controller type\n"));
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
         }
-        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
-        gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
-    } else {
-        TRACE2(("gdth_interrupt() unknown controller type\n"));
-        if (!gdth_polling)
-            GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return IRQ_HANDLED;
-    }
 
-    TRACE(("gdth_interrupt() index %d stat %d info %d\n",
-           IStatus,ha->status,ha->info));
+        TRACE(("gdth_interrupt() index %d stat %d info %d\n",
+               IStatus,ha->status,ha->info));
 
-    if (gdth_from_wait) {
-        wait_hanum = hanum;
-        wait_index = (int)IStatus;
-    }
+        if (gdth_from_wait) {
+            wait_hanum = hanum;
+            wait_index = (int)IStatus;
+        }
 
-    if (IStatus == ASYNCINDEX) {
-        TRACE2(("gdth_interrupt() async. event\n"));
-        gdth_async_event(hanum);
-        if (!gdth_polling)
-            GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        gdth_next(hanum);
-        return IRQ_HANDLED;
-    } 
+        if (IStatus == ASYNCINDEX) {
+            TRACE2(("gdth_interrupt() async. event\n"));
+            gdth_async_event(hanum);
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+            gdth_next(hanum);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
+        } 
 
-    if (IStatus == SPEZINDEX) {
-        TRACE2(("Service unknown or not initialized !\n"));
-        ha->dvr.size = sizeof(ha->dvr.eu.driver);
-        ha->dvr.eu.driver.ionode = hanum;
-        gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
-        if (!gdth_polling)
-            GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return IRQ_HANDLED;
-    }
-    scp     = ha->cmd_tab[IStatus-2].cmnd;
-    Service = ha->cmd_tab[IStatus-2].service;
-    ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND;
-    if (scp == UNUSED_CMND) {
-        TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
-        ha->dvr.size = sizeof(ha->dvr.eu.driver);
-        ha->dvr.eu.driver.ionode = hanum;
-        ha->dvr.eu.driver.index = IStatus;
-        gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
-        if (!gdth_polling)
-            GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return IRQ_HANDLED;
-    }
-    if (scp == INTERNAL_CMND) {
-        TRACE(("gdth_interrupt() answer to internal command\n"));
+        if (IStatus == SPEZINDEX) {
+            TRACE2(("Service unknown or not initialized !\n"));
+            ha->dvr.size = sizeof(ha->dvr.eu.driver);
+            ha->dvr.eu.driver.ionode = hanum;
+            gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
+        }
+        scp     = ha->cmd_tab[IStatus-2].cmnd;
+        Service = ha->cmd_tab[IStatus-2].service;
+        ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND;
+        if (scp == UNUSED_CMND) {
+            TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
+            ha->dvr.size = sizeof(ha->dvr.eu.driver);
+            ha->dvr.eu.driver.ionode = hanum;
+            ha->dvr.eu.driver.index = IStatus;
+            gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
+        }
+        if (scp == INTERNAL_CMND) {
+            TRACE(("gdth_interrupt() answer to internal command\n"));
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
+        }
+
+        TRACE(("gdth_interrupt() sync. status\n"));
+        rval = gdth_sync_event(hanum,Service,IStatus,scp);
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return IRQ_HANDLED;
-    }
-
-    TRACE(("gdth_interrupt() sync. status\n"));
-    rval = gdth_sync_event(hanum,Service,IStatus,scp);
-    if (!gdth_polling)
-        GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-    if (rval == 2) {
-        gdth_putq(hanum,scp,scp->SCp.this_residual);
-    } else if (rval == 1) {
-#if LINUX_VERSION_CODE >= 0x02053C
-        GDTH_LOCK_SCSI_DONE(scp->device->host, flags);
-        scp->scsi_done(scp);
-        GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags);
-#elif LINUX_VERSION_CODE >= 0x020503
-        GDTH_LOCK_SCSI_DONE(scp->host, flags);
-        scp->scsi_done(scp);
-        GDTH_UNLOCK_SCSI_DONE(scp->host, flags);
-#else
-        GDTH_LOCK_SCSI_DONE(flags);
-        scp->scsi_done(scp);
-        GDTH_UNLOCK_SCSI_DONE(flags);
+        if (rval == 2) {
+            gdth_putq(hanum,scp,scp->SCp.this_residual);
+        } else if (rval == 1) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            GDTH_LOCK_SCSI_DONE(scp->device->host, flags);
+            scp->scsi_done(scp);
+            GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags);
+#else
+            GDTH_LOCK_SCSI_DONE(flags);
+            scp->scsi_done(scp);
+            GDTH_UNLOCK_SCSI_DONE(flags);
 #endif
+        }
+
+#ifdef INT_COAL
+        if (coalesced) {
+            /* go to the next status in the status buffer */
+            ++pcs;
+#ifdef GDTH_STATISTICS
+            ++act_int_coal;
+            if (act_int_coal > max_int_coal) {
+                max_int_coal = act_int_coal;
+                printk("GDT: max_int_coal = %d\n",(ushort)max_int_coal);
+            }
+#endif      
+            /* see if there is another status */
+            if (pcs->status == 0)    
+                /* Stop the coalesce loop */
+                next = FALSE;
+        }
+    } while (next);
+
+    /* coalescing only for new GDT_PCIMPR controllers available */      
+    if (ha->type == GDT_PCIMPR && coalesced) {
+        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
     }
+#endif
+
     gdth_next(hanum);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     return IRQ_HANDLED;
+#endif
 }
 
 static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
@@ -3579,10 +3845,11 @@
            service,ha->status));
 
     if (service == SCREENSERVICE) {
-        msg  = (gdth_msg_str *)ha->pscratch;
-        ha->scratch_busy = FALSE;
+        msg  = ha->pmsg;
         TRACE(("len: %d, answer: %d, ext: %d, alen: %d\n",
                msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen));
+        if (msg->msg_len > MSGLEN+1)
+            msg->msg_len = MSGLEN+1;
         if (msg->msg_len)
             if (!(msg->msg_answer && msg->msg_ext)) {
                 msg->msg_text[msg->msg_len] = '\0';
@@ -3600,11 +3867,10 @@
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
             cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
-            cmdp->u.screen.su.msg.msg_addr  = ha->scratch_phys;
-            ha->scratch_busy = TRUE;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
             ha->cmd_offs_dpmem = 0;
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
-                + sizeof(ulong32);
+                + sizeof(ulong64);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
             gdth_release_event(hanum);
@@ -3635,11 +3901,10 @@
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
             cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
-            cmdp->u.screen.su.msg.msg_addr  = ha->scratch_phys;
-            ha->scratch_busy = TRUE;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
             ha->cmd_offs_dpmem = 0;
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
-                + sizeof(ulong32);
+                + sizeof(ulong64);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
             gdth_release_event(hanum);
@@ -3648,7 +3913,7 @@
         printk("\n");
 
     } else {
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
         t = scp->device->id;
 #else
@@ -3666,16 +3931,20 @@
             /* retry */
             return 2;
         }
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
         if (scp->SCp.Status == GDTH_MAP_SG) 
             pci_unmap_sg(ha->pdev,scp->request_buffer,
                          scp->use_sg,scp->SCp.Message);
         else if (scp->SCp.Status == GDTH_MAP_SINGLE) 
-            pci_unmap_single(ha->pdev,scp->SCp.dma_handle,
-                         scp->request_bufflen,scp->SCp.Message);
-        if (scp->SCp.buffer) 
-            pci_unmap_single(ha->pdev,(dma_addr_t)scp->SCp.buffer,
-						16,PCI_DMA_FROMDEVICE);
+            pci_unmap_page(ha->pdev,scp->SCp.dma_handle,
+                           scp->request_bufflen,scp->SCp.Message);
+        if (scp->SCp.buffer) {
+            dma_addr_t addr;
+            addr = (dma_addr_t)(ulong32)scp->SCp.buffer;
+            if (scp->host_scribble)
+                addr += (dma_addr_t)((ulong64)(ulong32)scp->host_scribble << 32);               
+            pci_unmap_page(ha->pdev,addr,16,PCI_DMA_FROMDEVICE);
+        }
 #endif
         if (ha->status == S_OK) {
             scp->SCp.Status = S_OK;
@@ -3754,10 +4023,7 @@
                     scp->sense_buffer[2] = NOT_READY;
                     scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
                 }
-#if LINUX_VERSION_CODE >= 0x010300
-                if (scp->done != gdth_scsi_done)
-#endif  
-                {
+                if (scp->done != gdth_scsi_done) {
                     ha->dvr.size = sizeof(ha->dvr.eu.sync);
                     ha->dvr.eu.sync.ionode  = hanum;
                     ha->dvr.eu.sync.service = service;
@@ -3946,13 +4212,11 @@
 static int gdth_async_event(int hanum)
 {
     gdth_ha_str *ha;
-    gdth_msg_str *msg;
     gdth_cmd_str *cmdp;
     int cmd_index;
 
     ha  = HADATA(gdth_ctr_tab[hanum]);
     cmdp= ha->pccb;
-    msg = (gdth_msg_str *)ha->pscratch;
     TRACE2(("gdth_async_event() ha %d serv %d\n",
             hanum,ha->service));
 
@@ -3968,11 +4232,10 @@
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
             cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE;
-            cmdp->u.screen.su.msg.msg_addr  = ha->scratch_phys;
-            ha->scratch_busy = TRUE;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
             ha->cmd_offs_dpmem = 0;
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
-                + sizeof(ulong32);
+                + sizeof(ulong64);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
             if (ha->type == GDT_EISA)
@@ -4192,10 +4455,11 @@
 GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp))
 {
     struct Scsi_Host *shp;
+    gdth_pci_str pcistr[MAXHA];
     gdth_ha_str *ha;
     ulong32 isa_bios;
     ushort eisa_slot;
-    int i,hanum,cnt,ctr;
+    int i,hanum,cnt,ctr,err;
     unchar b;
     
  
@@ -4218,11 +4482,11 @@
     TRACE(("gdth_detect()\n"));
 
     if (disable) {
-        printk("GDT: Controller driver disabled from command line !\n");
+        printk("GDT-HA: Controller driver disabled from command line !\n");
         return 0;
     }
 
-    printk("GDT: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR);
+    printk("GDT-HA: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR);
     /* initializations */
     gdth_polling = TRUE; b = 0;
     gdth_clear_events();
@@ -4232,6 +4496,7 @@
         /* scanning for controllers, at first: ISA controller */
         for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
             dma_addr_t scratch_dma_handle;
+            scratch_dma_handle = 0;
 
             if (gdth_ctr_count >= MAXHA) 
                 break;
@@ -4252,23 +4517,14 @@
                 printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
                        isa_bios,ha->irq,ha->drq);
 
-#if LINUX_VERSION_CODE >= 0x010346 
-                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha))
-#else
-                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
-#endif
-                {
+                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
                     printk("GDT-ISA: Unable to allocate IRQ\n");
                     scsi_unregister(shp);
                     continue;
                 }
                 if (request_dma(ha->drq,"gdth")) {
                     printk("GDT-ISA: Unable to allocate DMA channel\n");
-#if LINUX_VERSION_CODE >= 0x010346 
                     free_irq(ha->irq,ha);
-#else
-                    free_irq(ha->irq);
-#endif
                     scsi_unregister(shp);
                     continue;
                 }
@@ -4286,15 +4542,34 @@
 
                 ha->pccb = CMDDATA(shp);
                 ha->ccb_phys = 0L;
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                 ha->pdev = NULL;
                 ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
                                                     &scratch_dma_handle);
-                ha->scratch_phys = (ulong32)scratch_dma_handle;
+                ha->scratch_phys = scratch_dma_handle;
+                ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                                &scratch_dma_handle);
+                ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+                ha->coal_stat = (gdth_coal_status *)
+                    pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                        MAXOFFSETS, &scratch_dma_handle);
+                ha->coal_stat_phys = scratch_dma_handle;
+#endif
 #else
                 ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
                 if (ha->pscratch)
                     ha->scratch_phys = virt_to_bus(ha->pscratch);
+                ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA);
+                if (ha->pmsg)
+                    ha->msg_phys = virt_to_bus(ha->pmsg);
+#ifdef INT_COAL
+                ha->coal_stat = 
+                    scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, 
+                                     GFP_ATOMIC | GFP_DMA);
+                if (ha->coal_stat)
+                    ha->coal_stat_phys = virt_to_bus(ha->coal_stat);
+#endif
 #endif
                 ha->scratch_busy = FALSE;
                 ha->req_first = NULL;
@@ -4305,23 +4580,36 @@
                     ha->cmd_tab[i].cmnd = UNUSED_CMND;
                 ha->scan_mode = rescan ? 0x10 : 0;
 
-                if (ha->pscratch == NULL || !gdth_search_drives(hanum)) {
+                if (ha->pscratch == NULL || ha->pmsg == NULL || 
+                    !gdth_search_drives(hanum)) {
                     printk("GDT-ISA: Error during device scan\n");
                     --gdth_ctr_count;
                     --gdth_ctr_vcount;
-                    if (ha->pscratch != NULL) {
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                            MAXOFFSETS, ha->coal_stat,
+                                            ha->coal_stat_phys);
+#endif
+                    if (ha->pscratch)
                         pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
                                             ha->pscratch, ha->scratch_phys);
-#else
+                    if (ha->pmsg)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                            ha->pmsg, ha->msg_phys);
+#else
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        scsi_init_free((void *)ha->coal_stat, 
+                                       sizeof(gdth_coal_status) * MAXOFFSETS);
+#endif
+                    if (ha->pscratch)
                         scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+                    if (ha->pmsg)
+                        scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str));
 #endif
-                    }
-#if LINUX_VERSION_CODE >= 0x010346 
                     free_irq(ha->irq,ha);
-#else
-                    free_irq(ha->irq);
-#endif
                     scsi_unregister(shp);
                     continue;
                 }
@@ -4329,13 +4617,18 @@
                     hdr_channel = ha->bus_cnt;
                 ha->virt_bus = hdr_channel;
 
-#if LINUX_VERSION_CODE >= 0x020000
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
+    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                shp->highmem_io  = 0;
+#endif
+                if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) 
+                    shp->max_cmd_len = 16;
+#endif
                 shp->max_id      = ha->tid_cnt;
                 shp->max_lun     = MAXLUN;
                 shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-                if (virt_ctr)  
-#endif
-                {
+                if (virt_ctr) {
                     virt_ctr = 1;
                     /* register addit. SCSI channels as virtual controllers */
                     for (b = 1; b < ha->bus_cnt + 1; ++b) {
@@ -4358,6 +4651,7 @@
         /* scanning for EISA controllers */
         for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
             dma_addr_t scratch_dma_handle;
+            scratch_dma_handle = 0;
 
             if (gdth_ctr_count >= MAXHA) 
                 break;
@@ -4373,14 +4667,9 @@
                 }
                 /* controller found and initialized */
                 printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
-                        eisa_slot>>12,ha->irq);
+                       eisa_slot>>12,ha->irq);
 
-#if LINUX_VERSION_CODE >= 0x010346 
-                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha))
-#else
-                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
-#endif
-                {
+                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
                     printk("GDT-EISA: Unable to allocate IRQ\n");
                     scsi_unregister(shp);
                     continue;
@@ -4399,11 +4688,20 @@
 
                 ha->pccb = CMDDATA(shp);
                 ha->ccb_phys = 0L; 
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                 ha->pdev = NULL;
                 ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
                                                     &scratch_dma_handle);
-                ha->scratch_phys = (ulong32) scratch_dma_handle;
+                ha->scratch_phys = scratch_dma_handle;
+                ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                                &scratch_dma_handle);
+                ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+                ha->coal_stat = (gdth_coal_status *)
+                    pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                         MAXOFFSETS, &scratch_dma_handle);
+                ha->coal_stat_phys = scratch_dma_handle;
+#endif
                 ha->ccb_phys = 
                     pci_map_single(ha->pdev,ha->pccb,
                                    sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
@@ -4411,6 +4709,16 @@
                 ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
                 if (ha->pscratch)
                     ha->scratch_phys = virt_to_bus(ha->pscratch);
+                ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA);
+                if (ha->pmsg)
+                    ha->msg_phys = virt_to_bus(ha->pmsg);
+#ifdef INT_COAL
+                ha->coal_stat = 
+                    scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, 
+                                     GFP_ATOMIC | GFP_DMA);
+                if (ha->coal_stat)
+                    ha->coal_stat_phys = virt_to_bus(ha->coal_stat);
+#endif
                 ha->ccb_phys = virt_to_bus(ha->pccb);
 #endif
                 ha->scratch_busy = FALSE;
@@ -4419,28 +4727,42 @@
                 if (max_ids > 0 && max_ids < ha->tid_cnt)
                     ha->tid_cnt = max_ids;
                 for (i=0; i<GDTH_MAXCMDS; ++i)
-                     ha->cmd_tab[i].cmnd = UNUSED_CMND;
+                    ha->cmd_tab[i].cmnd = UNUSED_CMND;
                 ha->scan_mode = rescan ? 0x10 : 0;
 
-                if (ha->pscratch == NULL || !gdth_search_drives(hanum)) {
+                if (ha->pscratch == NULL || ha->pmsg == NULL || 
+                    !gdth_search_drives(hanum)) {
                     printk("GDT-EISA: Error during device scan\n");
                     --gdth_ctr_count;
                     --gdth_ctr_vcount;
-                    if (ha->pscratch != NULL) {
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                            MAXOFFSETS, ha->coal_stat,
+                                            ha->coal_stat_phys);
+#endif
+                    if (ha->pscratch)
                         pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
                                             ha->pscratch, ha->scratch_phys);
+                    if (ha->pmsg)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                            ha->pmsg, ha->msg_phys);
+                    if (ha->ccb_phys)
                         pci_unmap_single(ha->pdev,ha->ccb_phys,
-                                         sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+                                        sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
 #else
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        scsi_init_free((void *)ha->coal_stat, 
+                                       sizeof(gdth_coal_status) * MAXOFFSETS);
+#endif
+                    if (ha->pscratch)
                         scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+                    if (ha->pmsg)
+                        scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str));
 #endif
-                    }
-#if LINUX_VERSION_CODE >= 0x010346 
                     free_irq(ha->irq,ha);
-#else
-                    free_irq(ha->irq);
-#endif
                     scsi_unregister(shp);
                     continue;
                 }
@@ -4448,13 +4770,18 @@
                     hdr_channel = ha->bus_cnt;
                 ha->virt_bus = hdr_channel;
 
-#if LINUX_VERSION_CODE >= 0x020000
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
+    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                shp->highmem_io  = 0;
+#endif
+                if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) 
+                    shp->max_cmd_len = 16;
+#endif
                 shp->max_id      = ha->tid_cnt;
                 shp->max_lun     = MAXLUN;
                 shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-                if (virt_ctr)  
-#endif
-                {
+                if (virt_ctr) {
                     virt_ctr = 1;
                     /* register addit. SCSI channels as virtual controllers */
                     for (b = 1; b < ha->bus_cnt + 1; ++b) {
@@ -4475,124 +4802,173 @@
     }
 
     /* scanning for PCI controllers */
-#if LINUX_VERSION_CODE < 0x2015C
-    if (pcibios_present())
-#endif
-    {
-        gdth_pci_str pcistr[MAXHA];
+    cnt = gdth_search_pci(pcistr);
+    printk("GDT-HA: Found %d PCI Storage RAID Controllers\n",cnt);
+    gdth_sort_pci(pcistr,cnt);
+    for (ctr = 0; ctr < cnt; ++ctr) {
+        dma_addr_t scratch_dma_handle;
+        scratch_dma_handle = 0;
 
-        cnt = gdth_search_pci(pcistr);
-        printk("GDT: Found %d PCI Storage RAID Controllers\n",cnt);
-        gdth_sort_pci(pcistr,cnt);
-        for (ctr = 0; ctr < cnt; ++ctr) {
-            dma_addr_t scratch_dma_handle;
+        if (gdth_ctr_count >= MAXHA)
+            break;
+        shp = scsi_register(shtp,sizeof(gdth_ext_str));
+        if (shp == NULL)
+            continue;  
+
+        ha = HADATA(shp);
+        if (!gdth_init_pci(&pcistr[ctr],ha)) {
+            scsi_unregister(shp);
+            continue;
+        }
+        /* controller found and initialized */
+        printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+               pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
 
-            if (gdth_ctr_count >= MAXHA)
-                break;
-            shp = scsi_register(shtp,sizeof(gdth_ext_str));
-            if (shp == NULL)
-                continue;  
-
-            ha = HADATA(shp);
-            if (!gdth_init_pci(&pcistr[ctr],ha)) {
-                scsi_unregister(shp);
-                continue;
-            }
-            /* controller found and initialized */
-            printk("GDT CTR%d: Configuring GDT-PCI HA at %d/%d IRQ %u\n",
-                   ctr,pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
-
-#if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq, gdth_interrupt,
-                            SA_INTERRUPT|SA_SHIRQ, "gdth", ha))
-#else
-            if (request_irq(ha->irq, gdth_interrupt,
-                            SA_INTERRUPT|SA_SHIRQ, "gdth")) 
-#endif
-            {
-                printk("GDT-PCI: Unable to allocate IRQ\n");
-                scsi_unregister(shp);
-                continue;
-            }
-            shp->unchecked_isa_dma = 0;
-            shp->irq = ha->irq;
-            shp->dma_channel = 0xff;
-            hanum = gdth_ctr_count;
-            gdth_ctr_tab[gdth_ctr_count++] = shp;
-            gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
-            NUMDATA(shp)->hanum = (ushort)hanum;
-            NUMDATA(shp)->busnum= 0;
-
-            ha->pccb = CMDDATA(shp);
-            ha->ccb_phys = 0L;
-#if LINUX_VERSION_CODE >= 0x020400
-            ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
-                                                &scratch_dma_handle);
-            ha->scratch_phys = (ulong32)scratch_dma_handle;
-#else
-            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
-            if (ha->pscratch)
-                ha->scratch_phys = virt_to_bus(ha->pscratch);
-#endif
-            ha->scratch_busy = FALSE;
-            ha->req_first = NULL;
-            ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
-            if (max_ids > 0 && max_ids < ha->tid_cnt)
-                ha->tid_cnt = max_ids;
-            for (i=0; i<GDTH_MAXCMDS; ++i)
-                ha->cmd_tab[i].cmnd = UNUSED_CMND;
-            ha->scan_mode = rescan ? 0x10 : 0;
-
-            if (ha->pscratch == NULL || !gdth_search_drives(hanum)) {
-                printk("GDT-PCI: Error during device scan\n");
-                --gdth_ctr_count;
-                --gdth_ctr_vcount;
-                if (ha->pscratch != NULL) {
-#if LINUX_VERSION_CODE >= 0x020400
-                    pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
-                                        ha->pscratch, ha->scratch_phys);
-#else
-                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+        if (request_irq(ha->irq, gdth_interrupt,
+                        SA_INTERRUPT|SA_SHIRQ, "gdth", ha))
+        {
+            printk("GDT-PCI: Unable to allocate IRQ\n");
+            scsi_unregister(shp);
+            continue;
+        }
+        shp->unchecked_isa_dma = 0;
+        shp->irq = ha->irq;
+        shp->dma_channel = 0xff;
+        hanum = gdth_ctr_count;
+        gdth_ctr_tab[gdth_ctr_count++] = shp;
+        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+        NUMDATA(shp)->hanum = (ushort)hanum;
+        NUMDATA(shp)->busnum= 0;
+
+        ha->pccb = CMDDATA(shp);
+        ha->ccb_phys = 0L;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
+                                            &scratch_dma_handle);
+        ha->scratch_phys = scratch_dma_handle;
+        ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                        &scratch_dma_handle);
+        ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+        ha->coal_stat = (gdth_coal_status *)
+            pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                 MAXOFFSETS, &scratch_dma_handle);
+        ha->coal_stat_phys = scratch_dma_handle;
+#endif
+#else
+        ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+        if (ha->pscratch)
+            ha->scratch_phys = virt_to_bus(ha->pscratch);
+        ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA);
+        if (ha->pmsg)
+            ha->msg_phys = virt_to_bus(ha->pmsg);
+#ifdef INT_COAL
+        ha->coal_stat = 
+            scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, 
+                             GFP_ATOMIC | GFP_DMA);
+        if (ha->coal_stat)
+            ha->coal_stat_phys = virt_to_bus(ha->coal_stat);
 #endif
-                }
-#if LINUX_VERSION_CODE >= 0x010346 
-                free_irq(ha->irq,ha);
-#else
-                free_irq(ha->irq);
 #endif
-                scsi_unregister(shp);
-                continue;
-            }
+        ha->scratch_busy = FALSE;
+        ha->req_first = NULL;
+        ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
+        if (max_ids > 0 && max_ids < ha->tid_cnt)
+            ha->tid_cnt = max_ids;
+        for (i=0; i<GDTH_MAXCMDS; ++i)
+            ha->cmd_tab[i].cmnd = UNUSED_CMND;
+        ha->scan_mode = rescan ? 0x10 : 0;
+
+        err = FALSE;
+        if (ha->pscratch == NULL || ha->pmsg == NULL || 
+            !gdth_search_drives(hanum)) {
+            err = TRUE;
+        } else {
             if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
                 hdr_channel = ha->bus_cnt;
             ha->virt_bus = hdr_channel;
 
-#if LINUX_VERSION_CODE >= 0x020000
-            shp->max_id      = ha->tid_cnt;
-            shp->max_lun     = MAXLUN;
-            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-            if (virt_ctr)  
-#endif
-            {
-                virt_ctr = 1;
-                /* register addit. SCSI channels as virtual controllers */
-                for (b = 1; b < ha->bus_cnt + 1; ++b) {
-                    shp = scsi_register(shtp,sizeof(gdth_num_str));
-                    shp->unchecked_isa_dma = 0;
-                    shp->irq = ha->irq;
-                    shp->dma_channel = 0xff;
-                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                    NUMDATA(shp)->hanum = (ushort)hanum;
-                    NUMDATA(shp)->busnum = b;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            scsi_set_device(shp, &pcistr[ctr].pdev->dev);
+#else
+            scsi_set_pci_device(shp, pcistr[ctr].pdev);
+#endif
+            if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)||
+                /* 64-bit DMA only supported from FW >= x.43 */
+                (!ha->dma64_support)) {
+                if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) {
+                    printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum);
+                    err = TRUE;
+                }
+            } else {
+                shp->max_cmd_len = 16;
+                if (!pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffffffffffffULL)) {
+                    printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum);
+                } else if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) {
+                    printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum);
+                    err = TRUE;
                 }
-            }  
+            }
+#endif
+        }
 
-            GDTH_INIT_LOCK_HA(ha);
-            gdth_enable_int(hanum);
+        if (err) {
+            printk("GDT-PCI %d: Error during device scan\n", hanum);
+            --gdth_ctr_count;
+            --gdth_ctr_vcount;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#ifdef INT_COAL
+            if (ha->coal_stat)
+                pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                    MAXOFFSETS, ha->coal_stat,
+                                    ha->coal_stat_phys);
+#endif
+            if (ha->pscratch)
+                pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                    ha->pscratch, ha->scratch_phys);
+            if (ha->pmsg)
+                pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                    ha->pmsg, ha->msg_phys);
+#else
+#ifdef INT_COAL
+            if (ha->coal_stat)
+                scsi_init_free((void *)ha->coal_stat, 
+                               sizeof(gdth_coal_status) * MAXOFFSETS);
+#endif
+            if (ha->pscratch)
+                scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+            if (ha->pmsg)
+                scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str));
+#endif
+            free_irq(ha->irq,ha);
+            scsi_unregister(shp);
+            continue;
         }
-    }
 
+        shp->max_id      = ha->tid_cnt;
+        shp->max_lun     = MAXLUN;
+        shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+        if (virt_ctr) {
+            virt_ctr = 1;
+            /* register addit. SCSI channels as virtual controllers */
+            for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                shp = scsi_register(shtp,sizeof(gdth_num_str));
+                shp->unchecked_isa_dma = 0;
+                shp->irq = ha->irq;
+                shp->dma_channel = 0xff;
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum = b;
+            }
+        }  
+
+
+        GDTH_INIT_LOCK_HA(ha);
+        gdth_enable_int(hanum);
+    }
+    
     TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
     if (gdth_ctr_count > 0) {
 #ifdef GDTH_STATISTICS
@@ -4603,12 +4979,8 @@
         gdth_timer.function = gdth_timeout;
         add_timer(&gdth_timer);
 #endif
-#ifdef GDTH_IOCTL_CHRDEV
         major = register_chrdev(0,"gdth",&gdth_fops);
-#endif
-#if LINUX_VERSION_CODE >= 0x020100
         register_reboot_notifier(&gdth_notifier);
-#endif
     }
     gdth_polling = FALSE;
     return gdth_ctr_vcount;
@@ -4624,30 +4996,47 @@
     if (NUMDATA(shp)->busnum == 0) {
         hanum = NUMDATA(shp)->hanum;
         ha    = HADATA(gdth_ctr_tab[hanum]);
-#if LINUX_VERSION_CODE >= 0x010300
-        gdth_flush(hanum);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        if (ha->sdev) {
+            scsi_free_host_dev(ha->sdev);
+            ha->sdev = NULL;
+        }
 #endif
+        gdth_flush(hanum);
 
         if (shp->irq) {
-#if LINUX_VERSION_CODE >= 0x010346
             free_irq(shp->irq,ha);
-#else
-            free_irq(shp->irq);
-#endif
         }
 #ifndef __ia64__
         if (shp->dma_channel != 0xff) {
             free_dma(shp->dma_channel);
         }
 #endif
-#if LINUX_VERSION_CODE >= 0x020400
-        pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
-            ha->pscratch, ha->scratch_phys);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#ifdef INT_COAL
+        if (ha->coal_stat)
+            pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
+#endif
+        if (ha->pscratch)
+            pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                ha->pscratch, ha->scratch_phys);
+        if (ha->pmsg)
+            pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                ha->pmsg, ha->msg_phys);
         if (ha->ccb_phys)
             pci_unmap_single(ha->pdev,ha->ccb_phys,
                              sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
 #else
-        scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#ifdef INT_COAL
+        if (ha->coal_stat)
+            scsi_init_free((void *)ha->coal_stat, 
+                           sizeof(gdth_coal_status) * MAXOFFSETS);
+#endif
+        if (ha->pscratch)
+            scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+        if (ha->pmsg)
+            scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str));
 #endif
         gdth_ctr_released++;
         TRACE2(("gdth_release(): HA %d of %d\n", 
@@ -4657,12 +5046,8 @@
 #ifdef GDTH_STATISTICS
             del_timer(&gdth_timer);
 #endif
-#ifdef GDTH_IOCTL_CHRDEV
             unregister_chrdev(major,"gdth");
-#endif
-#if LINUX_VERSION_CODE >= 0x020100
             unregister_reboot_notifier(&gdth_notifier);
-#endif
         }
     }
 
@@ -4715,6 +5100,7 @@
     return ((const char *)ha->binfo.type_string);
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 /* old error handling */
 int gdth_abort(Scsi_Cmnd *scp)
 {
@@ -4722,17 +5108,13 @@
     return SCSI_ABORT_SNOOZE;
 }
 
-#if LINUX_VERSION_CODE >= 0x010346
 int gdth_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
-#else
-int gdth_reset(Scsi_Cmnd *scp)
-#endif
 {
     TRACE2(("gdth_reset()\n"));
     return SCSI_RESET_PUNT;
 }
+#endif
 
-#if LINUX_VERSION_CODE >= 0x02015F
 /* new error handling */
 int gdth_eh_abort(Scsi_Cmnd *scp)
 {
@@ -4755,7 +5137,7 @@
     unchar b;
 
     TRACE2(("gdth_eh_bus_reset()\n"));
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     hanum = NUMDATA(scp->device->host)->hanum;
     b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
 #else
@@ -4768,7 +5150,7 @@
     GDTH_LOCK_HA(ha, flags);
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         cmnd = ha->cmd_tab[i].cmnd;
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         if (!SPECIAL_SCP(cmnd) && cmnd->device->channel == b)
 #else
         if (!SPECIAL_SCP(cmnd) && cmnd->channel == b)
@@ -4813,15 +5195,12 @@
     TRACE2(("gdth_eh_host_reset()\n"));
     return FAILED;
 }
-#endif
 
 
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
-#elif LINUX_VERSION_CODE >= 0x010300
-int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
 #else
-int gdth_bios_param(Disk *disk,int dev,int *ip)
+int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
 #endif
 {
     unchar b, t;
@@ -4830,7 +5209,7 @@
     struct scsi_device *sd;
     unsigned capacity;
 
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     sd = sdev;
     capacity = cap;
 #else
@@ -4872,7 +5251,7 @@
     scp->SCp.sent_command = -1;
     scp->SCp.Status = GDTH_MAP_NONE;
     scp->SCp.buffer = (struct scatterlist *)NULL;
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     hanum = NUMDATA(scp->device->host)->hanum;
 #else
     hanum = NUMDATA(scp->host)->hanum;
@@ -4882,19 +5261,28 @@
 #endif
 
     priority = DEFAULT_PRI;
-#if LINUX_VERSION_CODE >= 0x010300
     if (scp->done == gdth_scsi_done)
         priority = scp->SCp.this_residual;
-#endif
     gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
     gdth_putq( hanum, scp, priority );
     gdth_next( hanum );
     return 0;
 }
 
-#ifdef GDTH_IOCTL_CHRDEV
+
 static int gdth_open(struct inode *inode, struct file *filep)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    gdth_ha_str *ha;
+    int i;
+
+    for (i = 0; i < gdth_ctr_count; i++) {
+        ha = HADATA(gdth_ctr_tab[i]);
+        if (!ha->sdev)
+            ha->sdev = scsi_get_host_dev(gdth_ctr_tab[i]);
+    }
+#endif
+
     TRACE(("gdth_open()\n"));
     return 0;
 }
@@ -4907,537 +5295,578 @@
 
 static int ioc_event(unsigned long arg)
 {
-        gdth_ioctl_event evt;
-        gdth_ha_str *ha;
-        ulong flags;
-
-        if (copy_from_user(&evt, (char *)arg, sizeof(gdth_ioctl_event)) ||
-            evt.ionode >= gdth_ctr_count)
-            return -EFAULT;
-        ha = HADATA(gdth_ctr_tab[evt.ionode]);
+    gdth_ioctl_event evt;
+    gdth_ha_str *ha;
+    ulong flags;
 
-        if (evt.erase == 0xff) {
-            if (evt.event.event_source == ES_TEST)
-                evt.event.event_data.size=sizeof(evt.event.event_data.eu.test); 
-            else if (evt.event.event_source == ES_DRIVER)
-                evt.event.event_data.size=sizeof(evt.event.event_data.eu.driver); 
-            else if (evt.event.event_source == ES_SYNC)
-                evt.event.event_data.size=sizeof(evt.event.event_data.eu.sync); 
-            else
-                evt.event.event_data.size=sizeof(evt.event.event_data.eu.async);
-            GDTH_LOCK_HA(ha, flags);
-            gdth_store_event(ha, evt.event.event_source, evt.event.event_idx,
-                             &evt.event.event_data);
-            GDTH_UNLOCK_HA(ha, flags);
-        } else if (evt.erase == 0xfe) {
-            gdth_clear_events();
-        } else if (evt.erase == 0) {
-            evt.handle = gdth_read_event(ha, evt.handle, &evt.event);
-        } else {
-            gdth_readapp_event(ha, evt.erase, &evt.event);
-        }     
-        if (copy_to_user((char *)arg, &evt, sizeof(gdth_ioctl_event)))
-            return -EFAULT;
-        return 0;
+    if (copy_from_user(&evt, (char *)arg, sizeof(gdth_ioctl_event)) ||
+        evt.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    ha = HADATA(gdth_ctr_tab[evt.ionode]);
+
+    if (evt.erase == 0xff) {
+        if (evt.event.event_source == ES_TEST)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.test); 
+        else if (evt.event.event_source == ES_DRIVER)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.driver); 
+        else if (evt.event.event_source == ES_SYNC)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.sync); 
+        else
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.async);
+        GDTH_LOCK_HA(ha, flags);
+        gdth_store_event(ha, evt.event.event_source, evt.event.event_idx,
+                         &evt.event.event_data);
+        GDTH_UNLOCK_HA(ha, flags);
+    } else if (evt.erase == 0xfe) {
+        gdth_clear_events();
+    } else if (evt.erase == 0) {
+        evt.handle = gdth_read_event(ha, evt.handle, &evt.event);
+    } else {
+        gdth_readapp_event(ha, evt.erase, &evt.event);
+    }     
+    if (copy_to_user((char *)arg, &evt, sizeof(gdth_ioctl_event)))
+        return -EFAULT;
+    return 0;
 }
 
 static int ioc_lockdrv(unsigned long arg)
 {
-        gdth_ioctl_lockdrv ldrv;
-        unchar i, j;
-        ulong flags;
-        gdth_ha_str *ha;
+    gdth_ioctl_lockdrv ldrv;
+    unchar i, j;
+    ulong flags;
+    gdth_ha_str *ha;
 
-        if (copy_from_user(&ldrv, (char *)arg, sizeof(gdth_ioctl_lockdrv)) ||
-            ldrv.ionode >= gdth_ctr_count)
-            return -EFAULT;
-        ha = HADATA(gdth_ctr_tab[ldrv.ionode]);
+    if (copy_from_user(&ldrv, (char *)arg, sizeof(gdth_ioctl_lockdrv)) ||
+        ldrv.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    ha = HADATA(gdth_ctr_tab[ldrv.ionode]);
  
-        for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) {
-            j = ldrv.drives[i];
-            if (j >= MAX_HDRIVES || !ha->hdr[j].present)
-                continue;
-            if (ldrv.lock) {
-                GDTH_LOCK_HA(ha, flags);
-                ha->hdr[j].lock = 1;
-                GDTH_UNLOCK_HA(ha, flags);
-                gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j); 
-                gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j); 
-            } else {
-                GDTH_LOCK_HA(ha, flags);
-                ha->hdr[j].lock = 0;
-                GDTH_UNLOCK_HA(ha, flags);
-                gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j); 
-                gdth_next(ldrv.ionode); 
-            }
-        } 
-        return 0;
+    for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) {
+        j = ldrv.drives[i];
+        if (j >= MAX_HDRIVES || !ha->hdr[j].present)
+            continue;
+        if (ldrv.lock) {
+            GDTH_LOCK_HA(ha, flags);
+            ha->hdr[j].lock = 1;
+            GDTH_UNLOCK_HA(ha, flags);
+            gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j); 
+            gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j); 
+        } else {
+            GDTH_LOCK_HA(ha, flags);
+            ha->hdr[j].lock = 0;
+            GDTH_UNLOCK_HA(ha, flags);
+            gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j); 
+            gdth_next(ldrv.ionode); 
+        }
+    } 
+    return 0;
 }
 
 static int ioc_resetdrv(unsigned long arg, char *cmnd)
 {
-        gdth_ioctl_reset res;
-        gdth_cmd_str cmd;
-        int hanum;
-        gdth_ha_str *ha;
-#if LINUX_VERSION_CODE >= 0x020503
-	Scsi_Request *srp;
-	Scsi_Device *sdev;
-#elif LINUX_VERSION_CODE >= 0x020322
-	Scsi_Cmnd *scp;
-	Scsi_Device *sdev;
-#else
-	Scsi_Cmnd scp;
-	Scsi_Device sdev;
+    gdth_ioctl_reset res;
+    gdth_cmd_str cmd;
+    int hanum;
+    gdth_ha_str *ha;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        Scsi_Request *srp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        Scsi_Cmnd *scp;
+#else
+        Scsi_Cmnd scp;
 #endif
 
-        if (copy_from_user(&res, (char *)arg, sizeof(gdth_ioctl_reset)) ||
-            res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES)
-            return -EFAULT;
-        hanum = res.ionode;
-        ha = HADATA(gdth_ctr_tab[hanum]);
+    if (copy_from_user(&res, (char *)arg, sizeof(gdth_ioctl_reset)) ||
+        res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES)
+        return -EFAULT;
+    hanum = res.ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
  
-        if (!ha->hdr[res.number].present)
-            return 0;
-        cmd.Service = CACHESERVICE;
-        cmd.OpCode = GDT_CLUST_RESET;
+    if (!ha->hdr[res.number].present)
+        return 0;
+    memset(&cmd, 0, sizeof(gdth_cmd_str));
+    cmd.Service = CACHESERVICE;
+    cmd.OpCode = GDT_CLUST_RESET;
+    if (ha->cache_feat & GDT_64BIT)
+        cmd.u.cache64.DeviceNo = res.number;
+    else
         cmd.u.cache.DeviceNo = res.number;
-#if LINUX_VERSION_CODE >= 0x020503
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        srp  = scsi_allocate_request(sdev, GFP_KERNEL);
-        if (!srp)
-            return -ENOMEM;
-        srp->sr_cmd_len = 12;
-        srp->sr_use_sg = 0;
-        gdth_do_req(srp, &cmd, cmnd, 30);
-        res.status = (ushort)srp->sr_command->SCp.Status;
-        scsi_release_request(srp);
-        scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        scp  = scsi_allocate_device(sdev, 1, FALSE);
-        if (!scp)
-            return -ENOMEM;
-        scp->cmd_len = 12;
-        scp->use_sg = 0;
-        gdth_do_cmd(scp, &cmd, cmnd, 30);
-        res.status = (ushort)scp->SCp.Status;
-        scsi_release_command(scp);
-        scsi_free_host_dev(sdev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+    gdth_do_req(srp, &cmd, cmnd, 30);
+    res.status = (ushort)srp->sr_command->SCp.Status;
+    scsi_release_request(srp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+    gdth_do_cmd(scp, &cmd, cmnd, 30);
+    res.status = (ushort)scp->SCp.Status;
+    scsi_release_command(scp);
 #else
-        memset(&sdev,0,sizeof(Scsi_Device));
-        memset(&scp, 0,sizeof(Scsi_Cmnd));
-        sdev.host = scp.host = gdth_ctr_tab[hanum];
-        sdev.id = scp.target = sdev.host->this_id;
-        scp.device = &sdev;
-        gdth_do_cmd(&scp, &cmd, cmnd, 30);
-        res.status = (ushort)scp.SCp.Status;
+    memset(&ha->sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+    ha->sdev.id = scp.target = ha->sdev.host->this_id;
+    scp.device = &ha->sdev;
+    gdth_do_cmd(&scp, &cmd, cmnd, 30);
+    res.status = (ushort)scp.SCp.Status;
 #endif
-        if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset)))
-            return -EFAULT;
-        return 0;
+    if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset)))
+        return -EFAULT;
+    return 0;
 }
 
 static int ioc_general(unsigned long arg, char *cmnd)
 {
-        gdth_ioctl_general gen;
-        char *buf = NULL;
-        ulong32 paddr; 
-        int hanum;
-	gdth_ha_str *ha; 
-#if LINUX_VERSION_CODE >= 0x020503
-	Scsi_Request *srp;
-	Scsi_Device *sdev;
-#elif LINUX_VERSION_CODE >= 0x020322
-	Scsi_Cmnd *scp;
-	Scsi_Device *sdev;
+    gdth_ioctl_general gen;
+    char *buf = NULL;
+    ulong64 paddr; 
+    int hanum;
+        gdth_ha_str *ha; 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        Scsi_Request *srp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        Scsi_Cmnd *scp;
 #else
-	Scsi_Cmnd scp;
-	Scsi_Device sdev;
+        Scsi_Cmnd scp;
 #endif
         
-        if (copy_from_user(&gen, (char *)arg, sizeof(gdth_ioctl_general)) ||
-            gen.ionode >= gdth_ctr_count)
+    if (copy_from_user(&gen, (char *)arg, sizeof(gdth_ioctl_general)) ||
+        gen.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    hanum = gen.ionode; 
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (gen.data_len + gen.sense_len != 0) {
+        if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len, 
+                                     FALSE, &paddr)))
             return -EFAULT;
-        hanum = gen.ionode; 
-        ha = HADATA(gdth_ctr_tab[hanum]);
-        if (gen.data_len + gen.sense_len != 0) {
-            if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len, 
-                                         FALSE, &paddr)))
-                return -EFAULT;
-            if (copy_from_user(buf, (char *)arg + sizeof(gdth_ioctl_general),  
-                               gen.data_len + gen.sense_len)) {
-                gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
-                return -EFAULT;
-            }
+        if (copy_from_user(buf, (char *)arg + sizeof(gdth_ioctl_general),  
+                           gen.data_len + gen.sense_len)) {
+            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+            return -EFAULT;
+        }
 
-            if (gen.command.OpCode == GDT_IOCTL) {
-                gen.command.u.ioctl.p_param = paddr;
-            } else if (gen.command.Service == CACHESERVICE) {
+        if (gen.command.OpCode == GDT_IOCTL) {
+            gen.command.u.ioctl.p_param = paddr;
+        } else if (gen.command.Service == CACHESERVICE) {
+            if (ha->cache_feat & GDT_64BIT) {
+                /* copy elements from 32-bit IOCTL structure */
+                gen.command.u.cache64.BlockCnt = gen.command.u.cache.BlockCnt;
+                gen.command.u.cache64.BlockNo = gen.command.u.cache.BlockNo;
+                gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo;
+                /* addresses */
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    gen.command.u.cache64.DestAddr = (ulong64)-1;
+                    gen.command.u.cache64.sg_canz = 1;
+                    gen.command.u.cache64.sg_lst[0].sg_ptr = paddr;
+                    gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.cache64.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.cache64.DestAddr = paddr;
+                    gen.command.u.cache64.sg_canz = 0;
+                }
+            } else {
                 if (ha->cache_feat & SCATTER_GATHER) {
                     gen.command.u.cache.DestAddr = 0xffffffff;
                     gen.command.u.cache.sg_canz = 1;
-                    gen.command.u.cache.sg_lst[0].sg_ptr = paddr;
+                    gen.command.u.cache.sg_lst[0].sg_ptr = (ulong32)paddr;
                     gen.command.u.cache.sg_lst[0].sg_len = gen.data_len;
                     gen.command.u.cache.sg_lst[1].sg_len = 0;
                 } else {
                     gen.command.u.cache.DestAddr = paddr;
                     gen.command.u.cache.sg_canz = 0;
                 }
-            } else if (gen.command.Service == SCSIRAWSERVICE) {
+            }
+        } else if (gen.command.Service == SCSIRAWSERVICE) {
+            if (ha->raw_feat & GDT_64BIT) {
+                /* copy elements from 32-bit IOCTL structure */
+                char cmd[16];
+                gen.command.u.raw64.sense_len = gen.command.u.raw.sense_len;
+                gen.command.u.raw64.bus = gen.command.u.raw.bus;
+                gen.command.u.raw64.lun = gen.command.u.raw.lun;
+                gen.command.u.raw64.target = gen.command.u.raw.target;
+                memcpy(cmd, gen.command.u.raw.cmd, 16);
+                memcpy(gen.command.u.raw64.cmd, cmd, 16);
+                gen.command.u.raw64.clen = gen.command.u.raw.clen;
+                gen.command.u.raw64.sdlen = gen.command.u.raw.sdlen;
+                gen.command.u.raw64.direction = gen.command.u.raw.direction;
+                /* addresses */
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    gen.command.u.raw64.sdata = (ulong64)-1;
+                    gen.command.u.raw64.sg_ranz = 1;
+                    gen.command.u.raw64.sg_lst[0].sg_ptr = paddr;
+                    gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.raw64.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.raw64.sdata = paddr;
+                    gen.command.u.raw64.sg_ranz = 0;
+                }
+                gen.command.u.raw64.sense_data = paddr + gen.data_len;
+            } else {
                 if (ha->raw_feat & SCATTER_GATHER) {
                     gen.command.u.raw.sdata = 0xffffffff;
                     gen.command.u.raw.sg_ranz = 1;
-                    gen.command.u.raw.sg_lst[0].sg_ptr = paddr;
+                    gen.command.u.raw.sg_lst[0].sg_ptr = (ulong32)paddr;
                     gen.command.u.raw.sg_lst[0].sg_len = gen.data_len;
                     gen.command.u.raw.sg_lst[1].sg_len = 0;
                 } else {
                     gen.command.u.raw.sdata = paddr;
                     gen.command.u.raw.sg_ranz = 0;
                 }
-                gen.command.u.raw.sense_data = paddr + gen.data_len;
-
-            } else {
-                gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
-                return -EFAULT;
+                gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len;
             }
+        } else {
+            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+            return -EFAULT;
         }
+    }
 
-#if LINUX_VERSION_CODE >= 0x020503
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        srp  = scsi_allocate_request(sdev, GFP_KERNEL);
-        if (!srp)
-            return -ENOMEM;
-        srp->sr_cmd_len = 12;
-        srp->sr_use_sg = 0;
-        gdth_do_req(srp, &gen.command, cmnd, gen.timeout);
-        gen.status = srp->sr_command->SCp.Status;
-        gen.info = srp->sr_command->SCp.Message;
-        scsi_release_request(srp);
-        scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        scp  = scsi_allocate_device(sdev, 1, FALSE);
-        if (!scp)
-            return -ENOMEM;
-        scp->cmd_len = 12;
-        scp->use_sg = 0;
-        gdth_do_cmd(scp, &gen.command, cmnd, gen.timeout);
-        gen.status = scp->SCp.Status;
-        gen.info = scp->SCp.Message;
-        scsi_release_command(scp);
-        scsi_free_host_dev(sdev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+    gdth_do_req(srp, &gen.command, cmnd, gen.timeout);
+    gen.status = srp->sr_command->SCp.Status;
+    gen.info = srp->sr_command->SCp.Message;
+    scsi_release_request(srp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+    gdth_do_cmd(scp, &gen.command, cmnd, gen.timeout);
+    gen.status = scp->SCp.Status;
+    gen.info = scp->SCp.Message;
+    scsi_release_command(scp);
 #else
-        memset(&sdev,0,sizeof(Scsi_Device));
-        memset(&scp, 0,sizeof(Scsi_Cmnd));
-        sdev.host = scp.host = gdth_ctr_tab[hanum];
-        sdev.id = scp.target = sdev.host->this_id;
-        scp.device = &sdev;
-        gdth_do_cmd(&scp, &gen.command, cmnd, gen.timeout);
-        gen.status = scp.SCp.Status;
-        gen.info = scp.SCp.Message;
+    memset(&ha->sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+    ha->sdev.id = scp.target = ha->sdev.host->this_id;
+    scp.device = &ha->sdev;
+    gdth_do_cmd(&scp, &gen.command, cmnd, gen.timeout);
+    gen.status = scp.SCp.Status;
+    gen.info = scp.SCp.Message;
 #endif
 
-        if (copy_to_user((char *)arg + sizeof(gdth_ioctl_general), buf, 
-                         gen.data_len + gen.sense_len)) {
-            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
-            return -EFAULT; 
-        } 
-        if (copy_to_user((char *)arg, &gen, 
-            sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) {
-            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
-            return -EFAULT;
-        }
+    if (copy_to_user((char *)arg + sizeof(gdth_ioctl_general), buf, 
+                     gen.data_len + gen.sense_len)) {
         gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
-        return 0;
+        return -EFAULT; 
+    } 
+    if (copy_to_user((char *)arg, &gen, 
+        sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) {
+        gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+        return -EFAULT;
+    }
+    gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+    return 0;
 }
  
 static int ioc_hdrlist(unsigned long arg, char *cmnd)
 {
-        gdth_ioctl_rescan rsc;
-        gdth_cmd_str cmd;
-        gdth_ha_str *ha;
-        unchar i;
-        int hanum;
-#if LINUX_VERSION_CODE >= 0x020503
-	Scsi_Request *srp;
-	Scsi_Device *sdev;
-#elif LINUX_VERSION_CODE >= 0x020322
-	Scsi_Cmnd *scp;
-	Scsi_Device *sdev;
+    gdth_ioctl_rescan rsc;
+    gdth_cmd_str cmd;
+    gdth_ha_str *ha;
+    unchar i;
+    int hanum;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *srp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    Scsi_Cmnd *scp;
 #else
-	Scsi_Cmnd scp;
-	Scsi_Device sdev;
+    Scsi_Cmnd scp;
 #endif
         
-        if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) ||
-            rsc.ionode >= gdth_ctr_count)
-            return -EFAULT;
-        hanum = rsc.ionode;
-        ha = HADATA(gdth_ctr_tab[hanum]);
+    if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) ||
+        rsc.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    hanum = rsc.ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(&cmd, 0, sizeof(gdth_cmd_str));
    
-#if LINUX_VERSION_CODE >= 0x020503
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        srp  = scsi_allocate_request(sdev, GFP_KERNEL);
-        if (!srp)
-            return -ENOMEM;
-        srp->sr_cmd_len = 12;
-        srp->sr_use_sg = 0;
-#elif LINUX_VERSION_CODE >= 0x020322
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        scp  = scsi_allocate_device(sdev, 1, FALSE);
-        if (!scp)
-            return -ENOMEM;
-        scp->cmd_len = 12;
-        scp->use_sg = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
 #else
-        memset(&sdev,0,sizeof(Scsi_Device));
-        memset(&scp, 0,sizeof(Scsi_Cmnd));
-        sdev.host = scp.host = gdth_ctr_tab[hanum];
-        sdev.id = scp.target = sdev.host->this_id;
-        scp.device = &sdev;
+    memset(&ha->sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+    ha->sdev.id = scp.target = ha->sdev.host->this_id;
+    scp.device = &ha->sdev;
 #endif
 
-        for (i = 0; i < MAX_HDRIVES; ++i) { 
-            if (!ha->hdr[i].present) {
-                rsc.hdr_list[i].bus = 0xff; 
-                continue;
-            } 
-            rsc.hdr_list[i].bus = ha->virt_bus;
-            rsc.hdr_list[i].target = i;
-            rsc.hdr_list[i].lun = 0;
-            rsc.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
-            if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { 
-                cmd.Service = CACHESERVICE;
-                cmd.OpCode = GDT_CLUST_INFO;
+    for (i = 0; i < MAX_HDRIVES; ++i) { 
+        if (!ha->hdr[i].present) {
+            rsc.hdr_list[i].bus = 0xff; 
+            continue;
+        } 
+        rsc.hdr_list[i].bus = ha->virt_bus;
+        rsc.hdr_list[i].target = i;
+        rsc.hdr_list[i].lun = 0;
+        rsc.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+        if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { 
+            cmd.Service = CACHESERVICE;
+            cmd.OpCode = GDT_CLUST_INFO;
+            if (ha->cache_feat & GDT_64BIT)
+                cmd.u.cache64.DeviceNo = i;
+            else
                 cmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020503
-                gdth_do_req(srp, &cmd, cmnd, 30);
-                if (srp->sr_command->SCp.Status == S_OK)
-                    rsc.hdr_list[i].cluster_type = srp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-                gdth_do_cmd(scp, &cmd, cmnd, 30);
-                if (scp->SCp.Status == S_OK)
-                    rsc.hdr_list[i].cluster_type = scp->SCp.Message;
-#else
-                gdth_do_cmd(&scp, &cmd, cmnd, 30);
-                if (scp.SCp.Status == S_OK)
-                    rsc.hdr_list[i].cluster_type = scp.SCp.Message;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(srp, &cmd, cmnd, 30);
+            if (srp->sr_command->SCp.Status == S_OK)
+                rsc.hdr_list[i].cluster_type = srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+            gdth_do_cmd(scp, &cmd, cmnd, 30);
+            if (scp->SCp.Status == S_OK)
+                rsc.hdr_list[i].cluster_type = scp->SCp.Message;
+#else
+            gdth_do_cmd(&scp, &cmd, cmnd, 30);
+            if (scp.SCp.Status == S_OK)
+                rsc.hdr_list[i].cluster_type = scp.SCp.Message;
 #endif
-            }
-        } 
-#if LINUX_VERSION_CODE >= 0x020503
-        scsi_release_request(srp);
-        scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
-        scsi_release_command(scp);
-        scsi_free_host_dev(sdev);
+        }
+    } 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(srp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scsi_release_command(scp);
 #endif       
  
-        if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan)))
-            return -EFAULT;
-        return 0;
+    if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan)))
+        return -EFAULT;
+    return 0;
 }
 
 static int ioc_rescan(unsigned long arg, char *cmnd)
 {
-        gdth_ioctl_rescan rsc;
-        gdth_cmd_str cmd;
-        ushort i, status, hdr_cnt;
-        ulong32 info;
-        int hanum, cyls, hds, secs;
-	ulong flags;
-	gdth_ha_str *ha; 
-#if LINUX_VERSION_CODE >= 0x020503
-	Scsi_Request *srp;
-	Scsi_Device *sdev;
-#elif LINUX_VERSION_CODE >= 0x020322
-	Scsi_Cmnd *scp;
-	Scsi_Device *sdev;
+    gdth_ioctl_rescan rsc;
+    gdth_cmd_str cmd;
+    ushort i, status, hdr_cnt;
+    ulong32 info;
+    int hanum, cyls, hds, secs;
+    ulong flags;
+    gdth_ha_str *ha; 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *srp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    Scsi_Cmnd *scp;
 #else
-	Scsi_Cmnd scp;
-	Scsi_Device sdev;
+    Scsi_Cmnd scp;
 #endif
         
-        if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) ||
-            rsc.ionode >= gdth_ctr_count)
-            return -EFAULT;
-        hanum = rsc.ionode;
-        ha = HADATA(gdth_ctr_tab[hanum]);
+    if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) ||
+        rsc.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    hanum = rsc.ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(&cmd, 0, sizeof(gdth_cmd_str));
 
-#if LINUX_VERSION_CODE >= 0x020503
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        srp  = scsi_allocate_request(sdev, GFP_KERNEL);
-        if (!srp)
-            return -ENOMEM;
-        srp->sr_cmd_len = 12;
-        srp->sr_use_sg = 0;
-#elif LINUX_VERSION_CODE >= 0x020322
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        scp  = scsi_allocate_device(sdev, 1, FALSE);
-        if (!scp)
-            return -ENOMEM;
-        scp->cmd_len = 12;
-        scp->use_sg = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
 #else
-        memset(&sdev,0,sizeof(Scsi_Device));
-        memset(&scp, 0,sizeof(Scsi_Cmnd));
-        sdev.host = scp.host = gdth_ctr_tab[hanum];
-        sdev.id = scp.target = sdev.host->this_id;
-        scp.device = &sdev;
+    memset(&ha->sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+    ha->sdev.id = scp.target = ha->sdev.host->this_id;
+    scp.device = &ha->sdev;
 #endif
      
-        if (rsc.flag == 0) {
-            /* old method: re-init. cache service */
-            cmd.Service = CACHESERVICE;
+    if (rsc.flag == 0) {
+        /* old method: re-init. cache service */
+        cmd.Service = CACHESERVICE;
+        if (ha->cache_feat & GDT_64BIT) {
+            cmd.OpCode = GDT_X_INIT_HOST;
+            cmd.u.cache64.DeviceNo = LINUX_OS;
+        } else {
             cmd.OpCode = GDT_INIT;
             cmd.u.cache.DeviceNo = LINUX_OS;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(srp, &cmd, cmnd, 30);
-            status = (ushort)srp->sr_command->SCp.Status;
-            info = (ulong32)srp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &cmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status;
-            info = (ulong32)scp->SCp.Message;
+        }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
 #else
-            gdth_do_cmd(&scp, &cmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
 #endif
-            i = 0;
-            hdr_cnt = (status == S_OK ? (ushort)info : 0);
-        } else {
-            i = rsc.hdr_no;
-            hdr_cnt = i + 1;
-        }
-        for (; i < hdr_cnt && i < MAX_HDRIVES; ++i) {
-            cmd.Service = CACHESERVICE;
-            cmd.OpCode = GDT_INFO;
+        i = 0;
+        hdr_cnt = (status == S_OK ? (ushort)info : 0);
+    } else {
+        i = rsc.hdr_no;
+        hdr_cnt = i + 1;
+    }
+    for (; i < hdr_cnt && i < MAX_HDRIVES; ++i) {
+        cmd.Service = CACHESERVICE;
+        cmd.OpCode = GDT_INFO;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd.u.cache64.DeviceNo = i;
+        else 
             cmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(srp, &cmd, cmnd, 30);
-            status = (ushort)srp->sr_command->SCp.Status;
-            info = (ulong32)srp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &cmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status;
-            info = (ulong32)scp->SCp.Message;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
 #else
-            gdth_do_cmd(&scp, &cmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
 #endif
-            GDTH_LOCK_HA(ha, flags);
-            rsc.hdr_list[i].bus = ha->virt_bus;
-            rsc.hdr_list[i].target = i;
-            rsc.hdr_list[i].lun = 0;
-            if (status != S_OK) {
-                ha->hdr[i].present = FALSE;
-            } else {
-                ha->hdr[i].present = TRUE;
-                ha->hdr[i].size = info;
-                /* evaluate mapping */
-                ha->hdr[i].size &= ~SECS32;
-                gdth_eval_mapping(ha->hdr[i].size,&cyls,&hds,&secs); 
-                ha->hdr[i].heads = hds;
-                ha->hdr[i].secs = secs;
-                /* round size */
-                ha->hdr[i].size = cyls * hds * secs;
-            }
-            GDTH_UNLOCK_HA(ha, flags);
-            if (status != S_OK)
-                continue; 
+        GDTH_LOCK_HA(ha, flags);
+        rsc.hdr_list[i].bus = ha->virt_bus;
+        rsc.hdr_list[i].target = i;
+        rsc.hdr_list[i].lun = 0;
+        if (status != S_OK) {
+            ha->hdr[i].present = FALSE;
+        } else {
+            ha->hdr[i].present = TRUE;
+            ha->hdr[i].size = info;
+            /* evaluate mapping */
+            ha->hdr[i].size &= ~SECS32;
+            gdth_eval_mapping(ha->hdr[i].size,&cyls,&hds,&secs); 
+            ha->hdr[i].heads = hds;
+            ha->hdr[i].secs = secs;
+            /* round size */
+            ha->hdr[i].size = cyls * hds * secs;
+        }
+        GDTH_UNLOCK_HA(ha, flags);
+        if (status != S_OK)
+            continue; 
+        
+        /* extended info, if GDT_64BIT, for drives > 2 TB */
+        /* but we need ha->info2, not yet stored in scp->SCp */
 
-            /* devtype, cluster info, R/W attribs */
-            cmd.Service = CACHESERVICE;
-            cmd.OpCode = GDT_DEVTYPE;
+        /* devtype, cluster info, R/W attribs */
+        cmd.Service = CACHESERVICE;
+        cmd.OpCode = GDT_DEVTYPE;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd.u.cache64.DeviceNo = i;
+        else
             cmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(srp, &cmd, cmnd, 30);
-            status = (ushort)srp->sr_command->SCp.Status;
-            info = (ulong32)srp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &cmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status;
-            info = (ulong32)scp->SCp.Message;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
 #else
-            gdth_do_cmd(&scp, &cmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
 #endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[i].devtype = (status == S_OK ? (ushort)info : 0);
-            GDTH_UNLOCK_HA(ha, flags);
+        GDTH_LOCK_HA(ha, flags);
+        ha->hdr[i].devtype = (status == S_OK ? (ushort)info : 0);
+        GDTH_UNLOCK_HA(ha, flags);
 
-            cmd.Service = CACHESERVICE;
-            cmd.OpCode = GDT_CLUST_INFO;
+        cmd.Service = CACHESERVICE;
+        cmd.OpCode = GDT_CLUST_INFO;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd.u.cache64.DeviceNo = i;
+        else
             cmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(srp, &cmd, cmnd, 30);
-            status = (ushort)srp->sr_command->SCp.Status;
-            info = (ulong32)srp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &cmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status;
-            info = (ulong32)scp->SCp.Message;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
 #else
-            gdth_do_cmd(&scp, &cmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
 #endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[i].cluster_type = 
-                ((status == S_OK && !shared_access) ? (ushort)info : 0);
-            GDTH_UNLOCK_HA(ha, flags);
-            rsc.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+        GDTH_LOCK_HA(ha, flags);
+        ha->hdr[i].cluster_type = 
+            ((status == S_OK && !shared_access) ? (ushort)info : 0);
+        GDTH_UNLOCK_HA(ha, flags);
+        rsc.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
 
-            cmd.Service = CACHESERVICE;
-            cmd.OpCode = GDT_RW_ATTRIBS;
+        cmd.Service = CACHESERVICE;
+        cmd.OpCode = GDT_RW_ATTRIBS;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd.u.cache64.DeviceNo = i;
+        else
             cmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(srp, &cmd, cmnd, 30);
-            status = (ushort)srp->sr_command->SCp.Status;
-            info = (ulong32)srp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &cmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status;
-            info = (ulong32)scp->SCp.Message;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
 #else
-            gdth_do_cmd(&scp, &cmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
 #endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[i].rw_attribs = (status == S_OK ? (ushort)info : 0);
-            GDTH_UNLOCK_HA(ha, flags);
-        }
-#if LINUX_VERSION_CODE >= 0x020503
-        scsi_release_request(srp);
-        scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
-        scsi_release_command(scp);
-        scsi_free_host_dev(sdev);
+        GDTH_LOCK_HA(ha, flags);
+        ha->hdr[i].rw_attribs = (status == S_OK ? (ushort)info : 0);
+        GDTH_UNLOCK_HA(ha, flags);
+    }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(srp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scsi_release_command(scp);
 #endif       
  
-        if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan)))
-            return -EFAULT;
-        return 0;
+    if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan)))
+        return -EFAULT;
+    return 0;
 }
   
 static int gdth_ioctl(struct inode *inode, struct file *filep,
                       unsigned int cmd, unsigned long arg)
 {
     gdth_ha_str *ha; 
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     Scsi_Cmnd *scp;
-    Scsi_Device *sdev;
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd *scp;
-    Scsi_Device *sdev;
 #else
     Scsi_Cmnd scp;
-    Scsi_Device sdev;
 #endif
     ulong flags;
     char cmnd[MAX_COMMAND_SIZE];   
@@ -5451,7 +5880,7 @@
       { 
         int cnt = gdth_ctr_count;
         if (put_user(cnt, (int *)arg))
-		return -EFAULT;
+                return -EFAULT;
         break;
       }
 
@@ -5459,7 +5888,7 @@
       { 
         int ver = (GDTH_VERSION<<8) | GDTH_SUBVERSION;
         if (put_user(ver, (int *)arg))
-		return -EFAULT;
+                return -EFAULT;
         break;
       }
       
@@ -5471,7 +5900,7 @@
         osv.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
         osv.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
         if (copy_to_user((char *)arg, &osv, sizeof(gdth_ioctl_osvers)))
-		return -EFAULT;
+                return -EFAULT;
         break;
       }
 
@@ -5507,13 +5936,13 @@
       }
         
       case GDTIOCTL_GENERAL:
-	return ioc_general(arg, cmnd);
+        return ioc_general(arg, cmnd);
 
       case GDTIOCTL_EVENT:
-	return ioc_event(arg);
+        return ioc_event(arg);
 
       case GDTIOCTL_LOCKDRV:
-	return ioc_lockdrv(arg);
+        return ioc_lockdrv(arg);
 
       case GDTIOCTL_LOCKCHN:
       {
@@ -5549,10 +5978,10 @@
       }
 
       case GDTIOCTL_RESCAN:
-	return ioc_rescan(arg, cmnd);
+        return ioc_rescan(arg, cmnd);
 
       case GDTIOCTL_HDRLIST:
-	return ioc_hdrlist(arg, cmnd);
+        return ioc_hdrlist(arg, cmnd);
 
       case GDTIOCTL_RESET_BUS:
       {
@@ -5563,11 +5992,11 @@
             res.ionode >= gdth_ctr_count)
             return -EFAULT;
         hanum = res.ionode; 
+        ha = HADATA(gdth_ctr_tab[hanum]);
 
-        /* Because we need a Scsi_Cmnd struct., we make a scsi_allocate device also for kernels >=2.5.x */        
-#if LINUX_VERSION_CODE >= 0x02053C
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-        scp  = scsi_get_command(sdev, GFP_KERNEL);
+        /* Because we need a Scsi_Cmnd struct., we make a scsi_allocate device also for kernels >=2.6.x */        
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        scp  = scsi_get_command(ha->sdev, GFP_KERNEL);
         if (!scp)
             return -ENOMEM;
         scp->cmd_len = 12;
@@ -5576,14 +6005,8 @@
         rval = gdth_eh_bus_reset(scp);
         res.status = (rval == SUCCESS ? S_OK : S_GENERR);
         scsi_put_command(scp);
-        scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
-        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-#if LINUX_VERSION_CODE >= 0x020503
-        scp  = scsi_allocate_device(sdev, 1);
-#else
-        scp  = scsi_allocate_device(sdev, 1, FALSE);
-#endif
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
         if (!scp)
             return -ENOMEM;
         scp->cmd_len = 12;
@@ -5592,18 +6015,15 @@
         rval = gdth_eh_bus_reset(scp);
         res.status = (rval == SUCCESS ? S_OK : S_GENERR);
         scsi_release_command(scp);
-        scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x02015F
-        memset(&sdev,0,sizeof(Scsi_Device));
+#else 
+        memset(&ha->sdev,0,sizeof(Scsi_Device));
         memset(&scp, 0,sizeof(Scsi_Cmnd));
-        sdev.host = scp.host = gdth_ctr_tab[hanum];
-        sdev.id = scp.target = sdev.host->this_id;
-        scp.device = &sdev;
+        ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+        ha->sdev.id = scp.target = ha->sdev.host->this_id;
+        scp.device = &ha->sdev;
         scp.channel = virt_ctr ? 0 : res.number;
         rval = gdth_eh_bus_reset(&scp);
         res.status = (rval == SUCCESS ? S_OK : S_GENERR);
-#else
-        res.status = S_OK;
 #endif
         if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset)))
             return -EFAULT;
@@ -5611,26 +6031,25 @@
       }
 
       case GDTIOCTL_RESET_DRV:
-	return ioc_resetdrv(arg, cmnd);
+        return ioc_resetdrv(arg, cmnd);
 
       default:
         break; 
     }
     return 0;
 }
-#endif
 
-#if LINUX_VERSION_CODE >= 0x010300
+
 /* flush routine */
 static void gdth_flush(int hanum)
 {
     int             i;
     gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     Scsi_Request    *srp;
     Scsi_Device     *sdev;
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd       *scp;
     Scsi_Device     *sdev;
 #else
@@ -5643,14 +6062,14 @@
     TRACE2(("gdth_flush() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
 
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
     srp  = scsi_allocate_request(sdev, GFP_KERNEL);
     if (!srp)
         return;
     srp->sr_cmd_len = 12;
     srp->sr_use_sg = 0;
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
     if (!scp)
@@ -5670,42 +6089,44 @@
             gdtcmd.BoardNode = LOCALBOARD;
             gdtcmd.Service = CACHESERVICE;
             gdtcmd.OpCode = GDT_FLUSH;
-            gdtcmd.u.cache.DeviceNo = i;
-            gdtcmd.u.cache.BlockNo = 1;
-            gdtcmd.u.cache.sg_canz = 0;
+            if (ha->cache_feat & GDT_64BIT) { 
+                gdtcmd.u.cache64.DeviceNo = i;
+                gdtcmd.u.cache64.BlockNo = 1;
+                gdtcmd.u.cache64.sg_canz = 0;
+            } else {
+                gdtcmd.u.cache.DeviceNo = i;
+                gdtcmd.u.cache.BlockNo = 1;
+                gdtcmd.u.cache.sg_canz = 0;
+            }
             TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
             gdth_do_req(srp, &gdtcmd, cmnd, 30);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
 #else
             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
 #endif
         }
     }
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     scsi_release_request(srp);
     scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     scsi_release_command(scp);
     scsi_free_host_dev(sdev);
 #endif
 }
 
 /* shutdown routine */
-#if LINUX_VERSION_CODE >= 0x020100
 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
-#else
-void gdth_halt(void)
-#endif
 {
     int             hanum;
 #ifndef __alpha__
     gdth_cmd_str    gdtcmd;
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     Scsi_Request    *srp;
     Scsi_Device     *sdev;
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd       *scp;
     Scsi_Device     *sdev;
 #else
@@ -5715,20 +6136,11 @@
     char            cmnd[MAX_COMMAND_SIZE];   
 #endif
 
-#if LINUX_VERSION_CODE >= 0x020100
     TRACE2(("gdth_halt() event %d\n",(int)event));
     if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
         return NOTIFY_DONE;
-#else
-    TRACE2(("gdth_halt()\n"));
-    if (halt_called) {
-        TRACE2(("already called\n"));
-        return;
-    }
-    halt_called = TRUE;
-#endif
 
-    printk("GDT: Flushing all host drives .. ");
+    printk("GDT-HA: Flushing all host drives .. ");
     for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
         gdth_flush(hanum);
 
@@ -5739,32 +6151,24 @@
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_RESET;
         TRACE2(("gdth_halt(): reset controller %d\n", hanum));
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
         srp  = scsi_allocate_request(sdev, GFP_KERNEL);
         if (!srp) {
-#if LINUX_VERSION_CODE >= 0x020100
             unregister_reboot_notifier(&gdth_notifier);
             return NOTIFY_OK;
-#else
-            return;
-#endif
         }
         srp->sr_cmd_len = 12;
         srp->sr_use_sg = 0;
         gdth_do_req(srp, &gdtcmd, cmnd, 10);
         scsi_release_request(srp);
         scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
         sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
         scp  = scsi_allocate_device(sdev, 1, FALSE);
         if (!scp) {
-#if LINUX_VERSION_CODE >= 0x020100
             unregister_reboot_notifier(&gdth_notifier);
             return NOTIFY_OK;
-#else
-            return;
-#endif
         }
         scp->cmd_len = 12;
         scp->use_sg = 0;
@@ -5786,15 +6190,12 @@
 #ifdef GDTH_STATISTICS
     del_timer(&gdth_timer);
 #endif
-#if LINUX_VERSION_CODE >= 0x020100
     unregister_reboot_notifier(&gdth_notifier);
     return NOTIFY_OK;
-#endif
 }
-#endif
 
 
-#if LINUX_VERSION_CODE < 0x020400 && !defined(MODULE)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) && !defined(MODULE)
 
 GDTH_INITFUNC(void, gdth_setup(char *str,int *ints)) 
 {    
@@ -5805,33 +6206,36 @@
 
 #else
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static Scsi_Host_Template driver_template = {
-#if LINUX_VERSION_CODE >= 0x02015F
-	.proc_name		= "gdth", 
-#else
-	.proc_dir		= &proc_scsi_gdth,
+        .proc_name              = "gdth", 
+        .proc_info              = gdth_proc_info,
+        .name                   = "GDT SCSI Disk Array Controller",
+        .detect                 = gdth_detect, 
+        .release                = gdth_release,
+        .info                   = gdth_info, 
+        .queuecommand           = gdth_queuecommand,
+        .eh_abort_handler       = gdth_eh_abort, 
+        .eh_device_reset_handler = gdth_eh_device_reset,
+        .eh_bus_reset_handler   = gdth_eh_bus_reset,
+        .eh_host_reset_handler  = gdth_eh_host_reset,
+        .bios_param             = gdth_bios_param,
+        .can_queue              = GDTH_MAXCMDS,
+        .this_id                = -1,
+        .sg_tablesize           = GDTH_MAXSG,
+        .cmd_per_lun            = GDTH_MAXC_P_L,
+        .unchecked_isa_dma      = 1,
+        .use_clustering         = ENABLE_CLUSTERING,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+        .use_new_eh_code        = 1,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
+        .highmem_io             = 1,
 #endif
-	.proc_info		= gdth_proc_info,
-	.name			= "GDT SCSI Disk Array Controller",
-	.detect			= gdth_detect, 
-	.release		= gdth_release,
-	.info			= gdth_info, 
-	.queuecommand		= gdth_queuecommand,
-	.eh_abort_handler	= gdth_eh_abort, 
-	.eh_device_reset_handler = gdth_eh_device_reset,
-	.eh_bus_reset_handler	= gdth_eh_bus_reset,
-	.eh_host_reset_handler	= gdth_eh_host_reset,
-	.bios_param		= gdth_bios_param,
-	.can_queue		= GDTH_MAXCMDS,
-	.this_id		= -1,
-	.sg_tablesize		= GDTH_MAXSG,
-	.cmd_per_lun		= GDTH_MAXC_P_L,
-	.unchecked_isa_dma	= 1,
-	.use_clustering		= ENABLE_CLUSTERING,
-#if LINUX_VERSION_CODE < 0x020501
-	.use_new_eh_code	= 1,
 #endif
 };
+#else
+static Scsi_Host_Template driver_template = GDTH;
+#endif
 
 #include "scsi_module.c"
 #ifndef MODULE
--- diff/drivers/scsi/gdth.h	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/gdth.h	2004-05-27 18:34:17.000000000 +0100
@@ -10,7 +10,7 @@
  *
  * <achim_leubner@adaptec.com>
  *
- * $Id: gdth.h,v 1.50 2003/09/17 08:29:58 achim Exp $
+ * $Id: gdth.h,v 1.57 2004/03/31 11:52:09 achim Exp $
  */
 
 #include <linux/version.h>
@@ -26,9 +26,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "2.08"
-#define GDTH_VERSION            2
-#define GDTH_SUBVERSION         8
+#define GDTH_VERSION_STR        "3.04"
+#define GDTH_VERSION            3
+#define GDTH_SUBVERSION         4
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
@@ -133,7 +133,12 @@
 /* new GDT Rx Controller */
 #define PCI_DEVICE_ID_VORTEX_GDTNEWRX   0x300
 #endif
-        
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX2
+/* new(2) GDT Rx Controller */
+#define PCI_DEVICE_ID_VORTEX_GDTNEWRX2  0x301
+#endif        
+
 #ifndef PCI_DEVICE_ID_INTEL_SRC
 /* Intel Storage RAID Controller */
 #define PCI_DEVICE_ID_INTEL_SRC         0x600
@@ -146,8 +151,7 @@
 
 /* limits */
 #define GDTH_SCRATCH    PAGE_SIZE               /* 4KB scratch buffer */
-#define GDTH_SCRATCH_ORD 0                      /* order 0 means 1 page */
-#define GDTH_MAXCMDS    124
+#define GDTH_MAXCMDS    120
 #define GDTH_MAXC_P_L   16                      /* max. cmds per lun */
 #define GDTH_MAX_RAW    2                       /* max. cmds per raw device */
 #define MAXOFFSETS      128
@@ -221,6 +225,8 @@
 #define GDT_CLUST_RESET 24                      /* releases the cluster drives*/
 #define GDT_FREEZE_IO   25                      /* freezes all IOs */
 #define GDT_UNFREEZE_IO 26                      /* unfreezes all IOs */
+#define GDT_X_INIT_HOST 29                      /* ext. init: 64 bit support */
+#define GDT_X_INFO      30                      /* ext. info for drives>2TB */
 
 /* raw service commands */
 #define GDT_RESERVE     14                      /* reserve dev. to raw serv. */
@@ -230,9 +236,11 @@
 #define GDT_RESET_BUS   18                      /* reset bus */
 #define GDT_SCAN_START  19                      /* start device scan */
 #define GDT_SCAN_END    20                      /* stop device scan */  
+#define GDT_X_INIT_RAW  21                      /* ext. init: 64 bit support */
 
 /* screen service commands */
 #define GDT_REALTIME    3                       /* realtime clock to screens. */
+#define GDT_X_INIT_SCR  4                       /* ext. init: 64 bit support */
 
 /* IOCTL command defines */
 #define SCSI_DR_INFO    0x00                    /* SCSI drive info */                   
@@ -254,6 +262,8 @@
 #define CACHE_DRV_INFO  0x07                    /* cache drive info */
 #define BOARD_FEATURES  0x15                    /* controller features */
 #define BOARD_INFO      0x28                    /* controller info */
+#define SET_PERF_MODES  0x82                    /* set mode (coalescing,..) */
+#define GET_PERF_MODES  0x83                    /* get mode */
 #define CACHE_READ_OEM_STRING_RECORD 0x84       /* read OEM string record */ 
 #define HOST_GET        0x10001L                /* get host drive list */
 #define IO_CHANNEL      0x00020000L             /* default IO channel */
@@ -266,6 +276,7 @@
 #define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
 #define S_RAW_SCSI      12                      /* raw serv.: target error */
 #define S_RAW_ILL       0xff                    /* raw serv.: illegal */
+#define S_NOFUNC        -2                      /* unknown function */
 #define S_CACHE_RESERV  -24                     /* cache: reserv. conflict */   
 
 /* timeout values */
@@ -307,7 +318,12 @@
 #define LOCALBOARD      0                       /* board node always 0 */
 #define ASYNCINDEX      0                       /* cmd index async. event */
 #define SPEZINDEX       1                       /* cmd index unknown service */
+#define COALINDEX       (GDTH_MAXCMDS + 2)
+
+/* features */
+#define SCATTER_GATHER  1                       /* s/g feature */
 #define GDT_WR_THROUGH  0x100                   /* WRITE_THROUGH supported */
+#define GDT_64BIT       0x200                   /* 64bit / drv>2TB support */
 
 #include "gdth_ioctl.h"
 
@@ -322,7 +338,40 @@
     char        msg_text[MSGLEN+2];             /* the message text */
 } PACKED gdth_msg_str;
 
+
 /* IOCTL data structures */
+
+/* Status coalescing buffer for returning multiple requests per interrupt */
+typedef struct {
+    ulong32     status;
+    ulong32     ext_status;
+    ulong32     info0;
+    ulong32     info1;
+} PACKED gdth_coal_status;
+
+/* performance mode data structure */
+typedef struct {
+    ulong32     version;            /* The version of this IOCTL structure. */
+    ulong32     st_mode;            /* 0=dis., 1=st_buf_addr1 valid, 2=both  */
+    ulong32     st_buff_addr1;      /* physical address of status buffer 1 */
+    ulong32     st_buff_u_addr1;    /* reserved for 64 bit addressing */
+    ulong32     st_buff_indx1;      /* reserved command idx. for this buffer */
+    ulong32     st_buff_addr2;      /* physical address of status buffer 1 */
+    ulong32     st_buff_u_addr2;    /* reserved for 64 bit addressing */
+    ulong32     st_buff_indx2;      /* reserved command idx. for this buffer */
+    ulong32     st_buff_size;       /* size of each buffer in bytes */
+    ulong32     cmd_mode;           /* 0 = mode disabled, 1 = cmd_buff_addr1 */ 
+    ulong32     cmd_buff_addr1;     /* physical address of cmd buffer 1 */   
+    ulong32     cmd_buff_u_addr1;   /* reserved for 64 bit addressing */
+    ulong32     cmd_buff_indx1;     /* cmd buf addr1 unique identifier */
+    ulong32     cmd_buff_addr2;     /* physical address of cmd buffer 1 */   
+    ulong32     cmd_buff_u_addr2;   /* reserved for 64 bit addressing */
+    ulong32     cmd_buff_indx2;     /* cmd buf addr1 unique identifier */
+    ulong32     cmd_buff_size;      /* size of each cmd bufer in bytes */
+    ulong32     reserved1;
+    ulong32     reserved2;
+} PACKED gdth_perf_modes;
+
 /* SCSI drive info */
 typedef struct {
     unchar      vendor[8];                      /* vendor string */
@@ -795,9 +844,7 @@
 
 /* PCI resources */
 typedef struct {
-#if LINUX_VERSION_CODE >= 0x02015C
     struct pci_dev      *pdev;
-#endif
     ushort              vendor_id;              /* vendor (ICP, Intel, ..) */
     ushort              device_id;              /* device ID (0,..,9) */
     ushort              subdevice_id;           /* sub device ID */
@@ -814,20 +861,28 @@
 typedef struct {
     ushort              oem_id;                 /* OEM */
     ushort              type;                   /* controller class */
-    ushort              raw_feat;               /* feat. raw service (s/g,..) */
     ulong32             stype;                  /* subtype (PCI: device ID) */
     ushort              subdevice_id;           /* sub device ID (PCI) */
     ushort              fw_vers;                /* firmware version */
-    ushort              cache_feat;             /* feat. cache serv. (s/g,..) */
+    ushort              cache_feat;             /* feat. cache serv. (s/g,..)*/
+    ushort              raw_feat;               /* feat. raw service (s/g,..)*/
+    ushort              screen_feat;            /* feat. raw service (s/g,..)*/
     ushort              bmic;                   /* BMIC address (EISA) */
     void                *brd;                   /* DPRAM address */
     ulong32             brd_phys;               /* slot number/BIOS address */
     gdt6c_plx_regs      *plx;                   /* PLX regs (new PCI contr.) */
     gdth_cmd_str        *pccb;                  /* address command structure */
     ulong32             ccb_phys;               /* phys. address */
+#ifdef INT_COAL
+    gdth_coal_status    *coal_stat;             /* buffer for coalescing int.*/
+    ulong64             coal_stat_phys;         /* phys. address */
+#endif
     char                *pscratch;              /* scratch (DMA) buffer */
-    ulong32             scratch_phys;           /* phys. address */
+    ulong64             scratch_phys;           /* phys. address */
     unchar              scratch_busy;           /* in use? */
+    unchar              dma64_support;          /* 64-bit DMA supported? */
+    gdth_msg_str        *pmsg;                  /* message buffer */
+    ulong64             msg_phys;               /* phys. address */
     unchar              scan_mode;              /* current scan mode */
     unchar              irq;                    /* IRQ */
     unchar              drq;                    /* DRQ (ISA controllers) */
@@ -848,11 +903,11 @@
         unchar          heads;                  /* mapping */
         unchar          secs;
         ushort          devtype;                /* further information */
-        ulong32         size;                   /* capacity */
+        ulong64         size;                   /* capacity */
         unchar          ldr_no;                 /* log. drive no. */
         unchar          rw_attribs;             /* r/w attributes */
         unchar          cluster_type;           /* cluster properties */
-        unchar          media_changed;          /* Flag:MOUNT/UNMOUNT occurred*/
+        unchar          media_changed;          /* Flag:MOUNT/UNMOUNT occured */
         ulong32         start_sec;              /* start sector */
     } hdr[MAX_LDRIVES];                         /* host drives */
     struct {
@@ -880,13 +935,19 @@
     gdth_bfeat_str      bfeat;                  /* controller features */
     gdth_binfo_str      binfo;                  /* controller info */
     gdth_evt_data       dvr;                    /* event structure */
-#if LINUX_VERSION_CODE >= 0x02015F
     spinlock_t          smp_lock;
-#endif
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     struct pci_dev      *pdev;
 #endif
     char                oem_name[8];
+#ifdef GDTH_DMA_STATISTICS
+    ulong               dma32_cnt, dma64_cnt;   /* statistics: DMA buffer */
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    Scsi_Device         *sdev;
+#else
+    Scsi_Device         sdev;
+#endif
 } gdth_ha_str;
 
 /* structure for scsi_register(), SCSI bus != 0 */
@@ -924,6 +985,12 @@
     ulong32     block_length;
 } PACKED gdth_rdcap_data;
 
+/* READ_CAPACITY (16) data format */
+typedef struct {
+    ulong64     last_block_no;
+    ulong32     block_length;
+} PACKED gdth_rdcap16_data;
+
 /* REQUEST_SENSE data format */
 typedef struct {
     unchar      errorcode;
@@ -965,42 +1032,48 @@
 int gdth_detect(Scsi_Host_Template *);
 int gdth_release(struct Scsi_Host *);
 int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *));
-int gdth_abort(Scsi_Cmnd *);
-#if LINUX_VERSION_CODE >= 0x010346
-int gdth_reset(Scsi_Cmnd *, unsigned int reset_flags);
-#else
-int gdth_reset(Scsi_Cmnd *);
-#endif
 const char *gdth_info(struct Scsi_Host *);
 
-#if LINUX_VERSION_CODE >= 0x020501
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 int gdth_bios_param(struct scsi_device *,struct block_device *,sector_t,int *);
 int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
-int gdth_eh_abort(Scsi_Cmnd *scp);
-int gdth_eh_device_reset(Scsi_Cmnd *scp);
-int gdth_eh_bus_reset(Scsi_Cmnd *scp);
-int gdth_eh_host_reset(Scsi_Cmnd *scp);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 int gdth_bios_param(Disk *,kdev_t,int *);
 int gdth_proc_info(char *,char **,off_t,int,int,int);
-int gdth_eh_abort(Scsi_Cmnd *scp);
-int gdth_eh_device_reset(Scsi_Cmnd *scp);
-int gdth_eh_bus_reset(Scsi_Cmnd *scp);
-int gdth_eh_host_reset(Scsi_Cmnd *scp);
-#elif LINUX_VERSION_CODE >= 0x02015F
+#else
 int gdth_bios_param(Disk *,kdev_t,int *);
 extern struct proc_dir_entry proc_scsi_gdth;
 int gdth_proc_info(char *,char **,off_t,int,int,int);
+int gdth_abort(Scsi_Cmnd *);
+int gdth_reset(Scsi_Cmnd *,unsigned int); 
+#define GDTH { proc_dir:        &proc_scsi_gdth,                 \
+               proc_info:       gdth_proc_info,                  \
+               name:            "GDT SCSI Disk Array Controller",\
+               detect:          gdth_detect,                     \
+               release:         gdth_release,                    \
+               info:            gdth_info,                       \
+               command:         NULL,                            \
+               queuecommand:    gdth_queuecommand,               \
+               eh_abort_handler: gdth_eh_abort,                  \
+               eh_device_reset_handler: gdth_eh_device_reset,    \
+               eh_bus_reset_handler: gdth_eh_bus_reset,          \
+               eh_host_reset_handler: gdth_eh_host_reset,        \
+               abort:           gdth_abort,                      \
+               reset:           gdth_reset,                      \
+               bios_param:      gdth_bios_param,                 \
+               can_queue:       GDTH_MAXCMDS,                    \
+               this_id:         -1,                              \
+               sg_tablesize:    GDTH_MAXSG,                      \
+               cmd_per_lun:     GDTH_MAXC_P_L,                   \
+               present:         0,                               \
+               unchecked_isa_dma: 1,                             \
+               use_clustering:  ENABLE_CLUSTERING,               \
+               use_new_eh_code: 1       /* use new error code */ }    
+#endif
+
 int gdth_eh_abort(Scsi_Cmnd *scp);
 int gdth_eh_device_reset(Scsi_Cmnd *scp);
 int gdth_eh_bus_reset(Scsi_Cmnd *scp);
 int gdth_eh_host_reset(Scsi_Cmnd *scp);
-#elif LINUX_VERSION_CODE >= 0x010300
-int gdth_bios_param(Disk *,kdev_t,int *);
-extern struct proc_dir_entry proc_scsi_gdth;
-int gdth_proc_info(char *,char **,off_t,int,int,int);
-#else
-int gdth_bios_param(Disk *,int,int *);
-#endif
-#endif
 
+#endif
--- diff/drivers/scsi/gdth_ioctl.h	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/gdth_ioctl.h	2004-05-27 18:34:17.000000000 +0100
@@ -2,7 +2,7 @@
 #define _GDTH_IOCTL_H
 
 /* gdth_ioctl.h
- * $Id: gdth_ioctl.h,v 1.11 2003/02/27 14:59:03 achim Exp $
+ * $Id: gdth_ioctl.h,v 1.14 2004/02/19 15:43:15 achim Exp $
  */
 
 /* IOCTLs */
@@ -21,8 +21,8 @@
 #define GDTIOCTL_RESCAN     (GDTIOCTL_MASK |11) /* rescan host drives */
 #define GDTIOCTL_RESET_DRV  (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */
 
-#define GDTIOCTL_MAGIC      0xaffe0004
-#define EVENT_SIZE          294 
+#define GDTIOCTL_MAGIC  0xaffe0004
+#define EVENT_SIZE      294 
 #define GDTH_MAXSG      32                      /* max. s/g elements */
 
 #define MAX_LDRIVES     255                     /* max. log. drive count */
@@ -35,7 +35,9 @@
 /* typedefs */
 #ifdef __KERNEL__
 typedef u32     ulong32;
+typedef u64     ulong64;
 #endif
+
 #define PACKED  __attribute__((packed))
 
 /* scatter/gather element */
@@ -44,6 +46,12 @@
     ulong32     sg_len;                         /* length */
 } PACKED gdth_sg_str;
 
+/* scatter/gather element - 64bit addresses */
+typedef struct {
+    ulong64     sg_ptr;                         /* address */
+    ulong32     sg_len;                         /* length */
+} PACKED gdth_sg64_str;
+
 /* command structure */
 typedef struct {
     ulong32     BoardNode;                      /* board node (always 0) */
@@ -59,17 +67,25 @@
             gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
         } PACKED cache;                         /* cache service cmd. str. */
         struct {
+            ushort      DeviceNo;               /* number of cache drive */
+            ulong64     BlockNo;                /* block number */
+            ulong32     BlockCnt;               /* block count */
+            ulong64     DestAddr;               /* dest. addr. (if s/g: -1) */
+            ulong32     sg_canz;                /* s/g element count */
+            gdth_sg64_str sg_lst[GDTH_MAXSG];   /* s/g list */
+        } PACKED cache64;                       /* cache service cmd. str. */
+        struct {
             ushort      param_size;             /* size of p_param buffer */
             ulong32     subfunc;                /* IOCTL function */
             ulong32     channel;                /* device */
-            ulong32     p_param;                /* buffer */
+            ulong64     p_param;                /* buffer */
         } PACKED ioctl;                         /* IOCTL command structure */
         struct {
             ushort      reserved;
             union {
                 struct {
                     ulong32  msg_handle;        /* message handle */
-                    ulong32  msg_addr;          /* message buffer address */
+                    ulong64  msg_addr;          /* message buffer address */
                 } PACKED msg;
                 unchar       data[12];          /* buffer for rtc data, ... */
             } su;
@@ -93,6 +109,24 @@
             ulong32     sg_ranz;                /* s/g element count */
             gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
         } PACKED raw;                           /* raw service cmd. struct. */
+        struct {
+            ushort      reserved;
+            ulong32     direction;              /* data direction */
+            ulong32     mdisc_time;             /* disc. time (0: no timeout)*/
+            ulong32     mcon_time;              /* connect time(0: no to.) */
+            ulong64     sdata;                  /* dest. addr. (if s/g: -1) */
+            ulong32     sdlen;                  /* data length (bytes) */
+            ulong32     clen;                   /* SCSI cmd. length(6,..,16) */
+            unchar      cmd[16];                /* SCSI command */
+            unchar      target;                 /* target ID */
+            unchar      lun;                    /* LUN */
+            unchar      bus;                    /* SCSI bus number */
+            unchar      priority;               /* only 0 used */
+            ulong32     sense_len;              /* sense data length */
+            ulong64     sense_data;             /* sense data addr. */
+            ulong32     sg_ranz;                /* s/g element count */
+            gdth_sg64_str sg_lst[GDTH_MAXSG];   /* s/g list */
+        } PACKED raw64;                         /* raw service cmd. struct. */
     } u;
     /* additional variables */
     unchar      Service;                        /* controller service */
@@ -236,7 +270,6 @@
 } gdth_iord_str;
 #endif
 
-#ifdef GDTH_IOCTL_CHRDEV
 /* GDTIOCTL_GENERAL */
 typedef struct {
     ushort ionode;                              /* controller number */
@@ -244,8 +277,8 @@
     ulong32 info;                               /* error info */ 
     ushort status;                              /* status */
     ulong data_len;                             /* data buffer size */
-    ulong sense_len;	                        /* sense buffer size */
-    gdth_cmd_str command;                       /* command */			
+    ulong sense_len;                            /* sense buffer size */
+    gdth_cmd_str command;                       /* command */                   
 } gdth_ioctl_general;
 
 /* GDTIOCTL_LOCKDRV */
@@ -310,6 +343,5 @@
     ushort number;                              /* bus/host drive number */
     ushort status;                              /* status */
 } gdth_ioctl_reset;
-#endif
 
 #endif
--- diff/drivers/scsi/gdth_proc.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/gdth_proc.c	2004-05-27 18:34:18.000000000 +0100
@@ -1,56 +1,80 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.37 2003/09/17 08:31:53 achim Exp $
+ * $Id: gdth_proc.c,v 1.42 2004/03/05 15:50:20 achim Exp $
  */
 
-#if LINUX_VERSION_CODE >= 0x020407
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
 #include <linux/completion.h>
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,   
                    int inout)
 {
     int hanum,busnum;
 
-    TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n",
-            length,hostno,(int)offset,inout));
+    TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
+            length,(int)offset,inout));
 
     hanum = NUMDATA(host)->hanum;
     busnum= NUMDATA(host)->busnum;
 
     if (inout)
-        return(gdth_set_info(buffer,length,hanum,busnum));
+        return(gdth_set_info(buffer,length,host,hanum,busnum));
     else
-        return(gdth_get_info(buffer,start,offset,length,hanum,busnum));
+        return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum));
 }
+#else
+int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno,   
+                   int inout)
+{
+    int hanum,busnum,i;
+
+    TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
+            length,(int)offset,inout));
+
+    for (i = 0; i < gdth_ctr_vcount; ++i) {
+        if (gdth_ctr_vtab[i]->host_no == hostno)
+            break;
+    }
+    if (i == gdth_ctr_vcount)
+        return(-EINVAL);
+
+    hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
+    busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
+
+    if (inout)
+        return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum));
+    else
+        return(gdth_get_info(buffer,start,offset,length,
+                             gdth_ctr_vtab[i],hanum,busnum));
+}
+#endif
 
-static int gdth_set_info(char *buffer,int length,int hanum,int busnum)
+static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
+                         int hanum,int busnum)
 {
     int             ret_val = -EINVAL;
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     Scsi_Request    *scp;
     Scsi_Device     *sdev;
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd       *scp;
     Scsi_Device     *sdev;
 #else
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
 #endif
-#ifdef GDTH_IOCTL_PROC
-    gdth_iowr_str   *piowr;
-    piowr = (gdth_iowr_str *)buffer;
-#endif
     TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
 
-#if LINUX_VERSION_CODE >= 0x020503
-    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sdev = scsi_get_host_dev(host);
     scp  = scsi_allocate_request(sdev, GFP_KERNEL);
     if (!scp)
         return -ENOMEM;
     scp->sr_cmd_len = 12;
     scp->sr_use_sg = 0;
-#elif LINUX_VERSION_CODE >= 0x020322
-    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    sdev = scsi_get_host_dev(host);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
     if (!scp)
         return -ENOMEM;
@@ -59,7 +83,7 @@
 #else
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = scp.host = gdth_ctr_tab[hanum];
+    sdev.host = scp.host = host;
     sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
 #endif
@@ -69,32 +93,21 @@
             buffer += 5;
             length -= 5;
             ret_val = gdth_set_asc_info( buffer, length, hanum, scp );
-#ifdef GDTH_IOCTL_PROC
-        } else if (piowr->magic == GDTIOCTL_MAGIC) {
-            ret_val = gdth_set_bin_info( buffer, length, hanum, scp );
-        } else {
-            printk("GDT: Wrong signature %x (%x required)!\n",
-                   piowr->magic, GDTIOCTL_MAGIC);
-            if (piowr->magic > GDTIOCTL_MAGIC)
-                printk("GDT: Please update your driver.\n");
-            else
-                printk("GDT: Please update your tool.\n");
-#endif
         }
     }
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     scsi_release_request(scp);
     scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     scsi_release_command(scp);
     scsi_free_host_dev(sdev);
 #endif
     return ret_val;
 }
          
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp)
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
 #else
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
@@ -105,7 +118,7 @@
     gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
     gdth_cpar_str   *pcpar;
-    ulong32         paddr;
+    ulong64         paddr;
 
     char            cmnd[MAX_COMMAND_SIZE];
     memset(cmnd, 0xff, 12);
@@ -139,11 +152,16 @@
                 found = TRUE;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_FLUSH;
-                gdtcmd.u.cache.DeviceNo = i;
-                gdtcmd.u.cache.BlockNo = 1;
-#if LINUX_VERSION_CODE >= 0x020503
+                if (ha->cache_feat & GDT_64BIT) {
+                    gdtcmd.u.cache64.DeviceNo = i;
+                    gdtcmd.u.cache64.BlockNo = 1;
+                } else {
+                    gdtcmd.u.cache.DeviceNo = i;
+                    gdtcmd.u.cache.BlockNo = 1;
+                }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
                 gdth_do_req(scp, &gdtcmd, cmnd, 30);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
 #else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
@@ -199,9 +217,9 @@
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
         pcpar->write_back = wb_mode==1 ? 0:1;
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         gdth_do_req(scp, &gdtcmd, cmnd, 30);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
         gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
 #else
         gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
@@ -215,562 +233,23 @@
     return(-EINVAL);
 }
 
-#ifdef GDTH_IOCTL_PROC
-#if LINUX_VERSION_CODE >= 0x020503
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Request *scp)
-#elif LINUX_VERSION_CODE >= 0x020322
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
-#else
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
-#endif
-{
-    unchar          i, j;
-    ushort          k, hdr_cnt, status;
-    gdth_ha_str     *ha;
-    gdth_iowr_str   *piowr;
-    gdth_iord_str   *piord;
-    gdth_cmd_str    *pcmd;
-    gdth_evt_str    *pevt;
-    ulong32         *ppadd, add_size, *ppadd2, add_size2, info, paddr;
-    ulong           flags;
-    gdth_cmd_str    gdtcmd;
-    int             drv_cyls, drv_hds, drv_secs;
- 
-    char            cmnd[MAX_COMMAND_SIZE];   
-    memset(cmnd, 0xff, 12);
-    memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
-
-    TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
-    piowr = (gdth_iowr_str *)buffer;
-    piord = NULL;
-    pcmd = NULL;
-    ppadd = ppadd2 = NULL;
-    add_size = add_size2 = 0;
-
-    if (length < GDTOFFSOF(gdth_iowr_str,iu))
-        return(-EINVAL);
-
-    switch (piowr->ioctl) {
-      case GDTIOCTL_GENERAL:
-        if (length < GDTOFFSOF(gdth_iowr_str,iu.general.data[0]))
-            return(-EINVAL);
-        pcmd = (gdth_cmd_str *)piowr->iu.general.command;
-        pcmd->Service = piowr->service;
-        if (pcmd->OpCode == GDT_IOCTL) {
-            ppadd = &pcmd->u.ioctl.p_param;
-            add_size = pcmd->u.ioctl.param_size;
-        } else if (piowr->service == CACHESERVICE) {
-            add_size = pcmd->u.cache.BlockCnt * SECTOR_SIZE;
-            if (ha->cache_feat & SCATTER_GATHER) {
-                ppadd = &pcmd->u.cache.sg_lst[0].sg_ptr;
-                pcmd->u.cache.DestAddr = 0xffffffff;
-                pcmd->u.cache.sg_lst[0].sg_len = add_size;
-                pcmd->u.cache.sg_canz = 1;
-            } else {
-                ppadd = &pcmd->u.cache.DestAddr;
-                pcmd->u.cache.sg_canz = 0;
-            }
-        } else if (piowr->service == SCSIRAWSERVICE) {
-            add_size = pcmd->u.raw.sdlen;
-            add_size2 = pcmd->u.raw.sense_len;
-            if (ha->raw_feat & SCATTER_GATHER) {
-                ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr;
-                pcmd->u.raw.sdata = 0xffffffff;
-                pcmd->u.raw.sg_lst[0].sg_len = add_size;
-                pcmd->u.raw.sg_ranz = 1;
-            } else {
-                ppadd = &pcmd->u.raw.sdata;
-                pcmd->u.raw.sg_ranz = 0;
-            }
-            ppadd2 = &pcmd->u.raw.sense_data;
-        } else {
-            return(-EINVAL);
-        }
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str)+add_size+add_size2,
-                               TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str) + add_size + add_size2;
-        if (add_size > 0) {
-            memcpy(piord->iu.general.data, piowr->iu.general.data, add_size);
-            *ppadd = paddr + GDTOFFSOF(gdth_iord_str, iu.general.data[0]);
-        }
-        if (add_size2 > 0) {
-            memcpy(piord->iu.general.data+add_size, piowr->iu.general.data, add_size2);
-            *ppadd2 = paddr + GDTOFFSOF(gdth_iord_str, iu.general.data[0]) + add_size2;
-        }
-        
-        /* do IOCTL */
-#if LINUX_VERSION_CODE >= 0x020503
-        gdth_do_req(scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp->sr_command->SCp.Message << 16) |
-            scp->sr_command->SCp.Status;
-#elif LINUX_VERSION_CODE >= 0x020322
-        gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
-#else
-        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
-#endif
-        break;
-
-      case GDTIOCTL_DRVERS:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        piord->iu.drvers.version = (GDTH_VERSION<<8) | GDTH_SUBVERSION;
-        break;
-
-      case GDTIOCTL_CTRTYPE:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
-            piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 0x10);
-        } else {
-            if (ha->type != GDT_PCIMPR) {
-                piord->iu.ctrtype.type = (unchar)((ha->stype<<4) + 6);
-            } else {
-                piord->iu.ctrtype.type = 
-                    (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe);
-                if (ha->stype >= 0x300)
-                    piord->iu.ctrtype.ext_type = 0x6000 | ha->subdevice_id;
-                else 
-                    piord->iu.ctrtype.ext_type = 0x6000 | ha->stype;
-            }
-            piord->iu.ctrtype.device_id = ha->stype;
-            piord->iu.ctrtype.sub_device_id = ha->subdevice_id;
-        }
-        piord->iu.ctrtype.info = ha->brd_phys;
-        piord->iu.ctrtype.oem_id = ha->oem_id;
-        break;
-
-      case GDTIOCTL_CTRCNT:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        piord->iu.ctrcnt.count = (ushort)gdth_ctr_count;
-        break;
-
-      case GDTIOCTL_OSVERS:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        piord->iu.osvers.version = (unchar)(LINUX_VERSION_CODE >> 16);
-        piord->iu.osvers.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
-        piord->iu.osvers.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
-        break;
-
-      case GDTIOCTL_LOCKDRV:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        for (i = 0; i < piowr->iu.lockdrv.drive_cnt; ++i) {
-            j = piowr->iu.lockdrv.drives[i];
-            if (j >= MAX_HDRIVES || !ha->hdr[j].present) 
-                continue;
-            if (piowr->iu.lockdrv.lock) {
-                GDTH_LOCK_HA(ha, flags);
-                ha->hdr[j].lock = 1;
-                GDTH_UNLOCK_HA(ha, flags);
-                gdth_wait_completion( hanum, ha->bus_cnt, j );
-                gdth_stop_timeout( hanum, ha->bus_cnt, j );
-            } else {
-                GDTH_LOCK_HA(ha, flags);
-                ha->hdr[j].lock = 0;
-                GDTH_UNLOCK_HA(ha, flags);
-                gdth_start_timeout( hanum, ha->bus_cnt, j );
-                gdth_next( hanum );
-            }
-        }
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        break;
-
-      case GDTIOCTL_LOCKCHN:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        i = piowr->iu.lockchn.channel;
-        if (i < ha->bus_cnt) {
-            if (piowr->iu.lockchn.lock) {
-                GDTH_LOCK_HA(ha, flags);
-                ha->raw[i].lock = 1;
-                GDTH_UNLOCK_HA(ha, flags);
-                for (j = 0; j < ha->tid_cnt; ++j) {
-                    gdth_wait_completion( hanum, i, j );
-                    gdth_stop_timeout( hanum, i, j );
-                }
-            } else {
-                GDTH_LOCK_HA(ha, flags);
-                ha->raw[i].lock = 0;
-                GDTH_UNLOCK_HA(ha, flags);
-                for (j = 0; j < ha->tid_cnt; ++j) {
-                    gdth_start_timeout( hanum, i, j );
-                    gdth_next( hanum );
-                }
-            }
-        }
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        break;
-
-      case GDTIOCTL_EVENT:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        if (piowr->iu.event.erase == 0xff) {
-            pevt = (gdth_evt_str *)piowr->iu.event.evt;
-            if (pevt->event_source == ES_TEST) 
-                pevt->event_data.size = sizeof(pevt->event_data.eu.test);
-            else if (pevt->event_source == ES_DRIVER) 
-                pevt->event_data.size = sizeof(pevt->event_data.eu.driver);
-            else if (pevt->event_source == ES_SYNC) 
-                pevt->event_data.size = sizeof(pevt->event_data.eu.sync);
-            else {
-                pevt->event_data.size = sizeof(pevt->event_data.eu.async);
-                gdth_log_event(&pevt->event_data, NULL);
-            }
-            GDTH_LOCK_HA(ha, flags);
-            gdth_store_event(ha, pevt->event_source, pevt->event_idx,
-                             &pevt->event_data);
-            GDTH_UNLOCK_HA(ha, flags);
-        } else if (piowr->iu.event.erase == 0xfe) {
-            gdth_clear_events();
-        } else if (piowr->iu.event.erase == 0) {
-            piord->iu.event.handle = 
-                gdth_read_event(ha,piowr->iu.event.handle,
-                                (gdth_evt_str *)piord->iu.event.evt);
-        } else {
-            piord->iu.event.handle = piowr->iu.event.handle;
-            gdth_readapp_event(ha, (unchar)piowr->iu.event.erase,
-                               (gdth_evt_str *)piord->iu.event.evt);
-        }
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        break;
-      
-      case GDTIOCTL_SCSI:
-#if LINUX_VERSION_CODE >= 0x020503
-        return(-EINVAL);
-#else
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        memcpy(cmnd, piowr->iu.scsi.cmd, 12);
-#if LINUX_VERSION_CODE >= 0x020322
-        scp->target = piowr->iu.scsi.target;
-        scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-        scp->cmd_len = piowr->iu.scsi.cmd_len;
-        gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
-#else
-        scp.target = piowr->iu.scsi.target;
-        scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-        scp.cmd_len = piowr->iu.scsi.cmd_len;
-        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
-#endif
-#endif
-        break;
-
-      case GDTIOCTL_RESET_BUS:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-#if LINUX_VERSION_CODE >= 0x02053C
-        {
-            Scsi_Device     *sdev;
-            Scsi_Cmnd       *scmnd;
-
-            sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
-            scmnd= scsi_get_command(sdev, GFP_KERNEL);
-            if (!scmnd)
-                return(-ENOMEM);
-            scmnd->device->host = scp->sr_host; 
-            scmnd->device->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-            piord->status = (ulong32)gdth_eh_bus_reset( scmnd );
-            if (piord->status == SUCCESS)
-                piord->status = S_OK;
-            else
-                piord->status = S_GENERR;
-            scsi_put_command(scmnd);
-            scsi_free_host_dev(sdev);
-        }
-#elif LINUX_VERSION_CODE >= 0x020503
-        {
-            Scsi_Cmnd scmnd;
-             
-            scmnd.host = scp->sr_host; 
-            scmnd.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-            piord->status = (ulong32)gdth_eh_bus_reset( &scmnd );
-            if (piord->status == SUCCESS)
-                piord->status = S_OK;
-            else
-                piord->status = S_GENERR;
-        }
-#elif LINUX_VERSION_CODE >= 0x020322
-        scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-        piord->status = (ulong32)gdth_eh_bus_reset( scp );
-        if (piord->status == SUCCESS)
-            piord->status = S_OK;
-        else
-            piord->status = S_GENERR;
-#elif LINUX_VERSION_CODE >= 0x02015F
-        scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-        piord->status = (ulong32)gdth_eh_bus_reset( &scp );
-        if (piord->status == SUCCESS)
-            piord->status = S_OK;
-        else
-            piord->status = S_GENERR;
-#else
-        piord->status = S_OK;
-#endif
-        break;
-
-      case GDTIOCTL_HDRLIST:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        for (i = 0; i < MAX_HDRIVES; ++i) {
-            if (ha->hdr[i].present) {
-                piord->iu.hdr_list[i].bus = ha->virt_bus;
-                piord->iu.hdr_list[i].target = i;
-                piord->iu.hdr_list[i].lun = 0;
-                piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
-                if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) {  
-                    gdtcmd.Service = CACHESERVICE;
-                    gdtcmd.OpCode = GDT_CLUST_INFO;
-                    gdtcmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020503
-                    gdth_do_req(scp, &gdtcmd, cmnd, 30);
-                    if (scp->sr_command->SCp.Status == S_OK)
-                        piord->iu.hdr_list[i].cluster_type = 
-                            (unchar)scp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                    if (scp->SCp.Status == S_OK)
-                        piord->iu.hdr_list[i].cluster_type = 
-                            (unchar)scp->SCp.Message;
-#else
-                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                    if (scp.SCp.Status == S_OK)
-                        piord->iu.hdr_list[i].cluster_type = 
-                            (unchar)scp.SCp.Message;
-#endif
-                }
-            } else {
-                piord->iu.hdr_list[i].bus = 0xff;
-            }
-        }
-        break;
-
-      case GDTIOCTL_RESCAN:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        if (piowr->iu.rescan.flag == 0) {
-            /* old method: scan all host drives 
-               re-initialize cache service to get host drive count
-            */
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_INIT;
-            gdtcmd.u.cache.DeviceNo = LINUX_OS;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->sr_command->SCp.Status; 
-            info = (ulong32)scp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            if (status != S_OK)
-                break;
-            k = 0;
-            hdr_cnt = (ushort)info;
-        } else {
-            k = piowr->iu.rescan.hdr_no;
-            hdr_cnt = k + 1;
-        }
-        if (hdr_cnt > MAX_HDRIVES)
-            hdr_cnt = MAX_HDRIVES;
-        /* scanning for host drives */
-        for (; k < hdr_cnt; ++k) {
-            /* info about host drive */
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_INFO;
-            gdtcmd.u.cache.DeviceNo = k;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->sr_command->SCp.Status; 
-            info = (ulong32)scp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            GDTH_LOCK_HA(ha, flags);
-            piord->iu.hdr_list[k].bus = ha->virt_bus;
-            piord->iu.hdr_list[k].target = k;
-            piord->iu.hdr_list[k].lun = 0;
-            if (status != S_OK) {
-                ha->hdr[k].present = FALSE;
-            } else {
-                ha->hdr[k].present = TRUE;
-                ha->hdr[k].size = info;
-                /* evaluate mapping (sectors per head, heads per cylinder) */
-                ha->hdr[k].size &= ~SECS32;
-                gdth_eval_mapping(ha->hdr[k].size,&drv_cyls,&drv_hds,&drv_secs);
-                ha->hdr[k].heads = (unchar)drv_hds;
-                ha->hdr[k].secs = (unchar)drv_secs;
-                /* round size */
-                ha->hdr[k].size = drv_cyls * drv_hds * drv_secs;
-            }
-            GDTH_UNLOCK_HA(ha, flags);
-            if (status != S_OK)
-                continue;       /* next host drive */
-
-            /* devtype, cluster info, R/W attributes */
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_DEVTYPE;
-            gdtcmd.u.cache.DeviceNo = k;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->sr_command->SCp.Status; 
-            info = (ulong32)scp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[k].devtype = 0;
-            if (status == S_OK)
-                ha->hdr[k].devtype = (ushort)info;
-            GDTH_UNLOCK_HA(ha, flags);
-
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_CLUST_INFO;
-            gdtcmd.u.cache.DeviceNo = k;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->sr_command->SCp.Status; 
-            info = (ulong32)scp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[k].cluster_type = 0;
-            if (status == S_OK && !shared_access)
-                ha->hdr[k].cluster_type = (ushort)info;
-            GDTH_UNLOCK_HA(ha, flags);
-            piord->iu.hdr_list[k].cluster_type = ha->hdr[k].cluster_type;
-
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_RW_ATTRIBS;
-            gdtcmd.u.cache.DeviceNo = k;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->sr_command->SCp.Status; 
-            info = (ulong32)scp->sr_command->SCp.Message;
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[k].rw_attribs = 0;
-            if (status == S_OK)
-                ha->hdr[k].rw_attribs = (ushort)info;
-            GDTH_UNLOCK_HA(ha, flags);
-        }
-        break;
-
-      case GDTIOCTL_RESET_DRV:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE, &paddr ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        i = piowr->iu.scsi.target;
-        if (ha->hdr[i].present) {
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_CLUST_RESET;
-            gdtcmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020503
-            gdth_do_req(scp, &gdtcmd, cmnd, 30);
-            piord->status = (ushort)scp->sr_command->SCp.Status; 
-#elif LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
-#endif
-        }
-        break;
-
-      default:
-        return(-EINVAL);
-    }
-    return length;
-}
-#endif
-
-static int gdth_get_info(char *buffer,char **start,off_t offset,
-                         int length,int hanum,int busnum)
+static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
+                         struct Scsi_Host *host,int hanum,int busnum)
 {
     int size = 0,len = 0;
     off_t begin = 0,pos = 0;
     gdth_ha_str *ha;
     int id, i, j, k, sec, flag;
     int no_mdrv = 0, drv_no, is_mirr;
-    ulong32 cnt, paddr;
+    ulong32 cnt;
+    ulong64 paddr;
 
     gdth_cmd_str gdtcmd;
     gdth_evt_str estr;
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     Scsi_Request *scp;
     Scsi_Device *sdev; 
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd *scp;
     Scsi_Device *sdev;
 #else
@@ -795,15 +274,15 @@
     TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
     ha = HADATA(gdth_ctr_tab[hanum]);
 
-#if LINUX_VERSION_CODE >= 0x020503
-    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sdev = scsi_get_host_dev(host);
     scp  = scsi_allocate_request(sdev, GFP_KERNEL);
     if (!scp)
         return -ENOMEM;
     scp->sr_cmd_len = 12;
     scp->sr_use_sg = 0;
-#elif LINUX_VERSION_CODE >= 0x020322
-    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    sdev = scsi_get_host_dev(host);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
     if (!scp)
         return -ENOMEM;
@@ -812,485 +291,415 @@
 #else
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = scp.host = gdth_ctr_tab[hanum];
+    sdev.host = scp.host = host;
     sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
 #endif
-
-#ifdef GDTH_IOCTL_PROC
-    /* ioctl from tool? */
-    if (!gdth_ioctl_check_bin(hanum, (ushort)length)) {
-#endif
-        /* request is i.e. "cat /proc/scsi/gdth/0" */ 
-        /* format: %-15s\t%-10s\t%-15s\t%s */
-        /* driver parameters */
-        size = sprintf(buffer+len,"Driver Parameters:\n");
-        len += size;  pos = begin + len;
-        if (reserve_list[0] == 0xff)
-            strcpy(hrec, "--");
-        else {
-            sprintf(hrec, "%d", reserve_list[0]);
-            for (i = 1;  i < MAX_RES_ARGS; i++) {
-                if (reserve_list[i] == 0xff) 
-                    break;
-                sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
-            }
+    
+    
+    /* request is i.e. "cat /proc/scsi/gdth/0" */ 
+    /* format: %-15s\t%-10s\t%-15s\t%s */
+    /* driver parameters */
+    size = sprintf(buffer+len,"Driver Parameters:\n");
+    len += size;  pos = begin + len;
+    if (reserve_list[0] == 0xff)
+        strcpy(hrec, "--");
+    else {
+        sprintf(hrec, "%d", reserve_list[0]);
+        for (i = 1;  i < MAX_RES_ARGS; i++) {
+            if (reserve_list[i] == 0xff) 
+                break;
+            sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
         }
-        size = sprintf(buffer+len,
-                       " reserve_mode: \t%d         \treserve_list:  \t%s\n",
-                       reserve_mode, hrec);
-        len += size;  pos = begin + len;
-        size = sprintf(buffer+len,
-                       " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
-                       max_ids, hdr_channel);
-        len += size;  pos = begin + len;
+    }
+    size = sprintf(buffer+len,
+                   " reserve_mode: \t%d         \treserve_list:  \t%s\n",
+                   reserve_mode, hrec);
+    len += size;  pos = begin + len;
+    size = sprintf(buffer+len,
+                   " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
+                   max_ids, hdr_channel);
+    len += size;  pos = begin + len;
+
+    /* controller information */
+    size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
+    len += size;  pos = begin + len;
+    if (virt_ctr)
+        sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
+    else
+        strcpy(hrec, ha->binfo.type_string);
+    size = sprintf(buffer+len,
+                   " Number:       \t%d         \tName:          \t%s\n",
+                   hanum, hrec);
+    len += size;  pos = begin + len;
+
+    if (ha->more_proc)
+        sprintf(hrec, "%d.%02d.%02d-%c%03X", 
+                (unchar)(ha->binfo.upd_fw_ver>>24),
+                (unchar)(ha->binfo.upd_fw_ver>>16),
+                (unchar)(ha->binfo.upd_fw_ver),
+                ha->bfeat.raid ? 'R':'N',
+                ha->binfo.upd_revision);
+    else
+        sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
+                (unchar)(ha->cpar.version));
 
-        /* controller information */
-        size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
-        len += size;  pos = begin + len;
-        if (virt_ctr)
-            sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
-        else
-            strcpy(hrec, ha->binfo.type_string);
+    size = sprintf(buffer+len,
+                   " Driver Ver.:  \t%-10s\tFirmware Ver.: \t%s\n",
+                   GDTH_VERSION_STR, hrec);
+    len += size;  pos = begin + len;
+ 
+    if (ha->more_proc) {
+        /* more information: 1. about controller */
         size = sprintf(buffer+len,
-                       " Number:       \t%d         \tName:          \t%s\n",
-                       hanum, hrec);
+                       " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
+                       ha->binfo.ser_no, ha->binfo.memsize / 1024);
         len += size;  pos = begin + len;
+    }
 
-        if (ha->more_proc)
-            sprintf(hrec, "%d.%02d.%02d-%c%03X", 
-                    (unchar)(ha->binfo.upd_fw_ver>>24),
-                    (unchar)(ha->binfo.upd_fw_ver>>16),
-                    (unchar)(ha->binfo.upd_fw_ver),
-                    ha->bfeat.raid ? 'R':'N',
-                    ha->binfo.upd_revision);
-        else
-            sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
-                    (unchar)(ha->cpar.version));
+#ifdef GDTH_DMA_STATISTICS
+    /* controller statistics */
+    size = sprintf(buffer+len,"\nController Statistics:\n");
+    len += size;  pos = begin + len;
+    size = sprintf(buffer+len,
+                   " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n",
+                   ha->dma32_cnt, ha->dma64_cnt);
+    len += size;  pos = begin + len;
+#endif
 
-        size = sprintf(buffer+len,
-                       " Driver Ver.:  \t%-10s\tFirmware Ver.: \t%s\n",
-                       GDTH_VERSION_STR, hrec);
+    if (pos < offset) {
+        len = 0;
+        begin = pos;
+    }
+    if (pos > offset + length)
+        goto stop_output;
+
+    if (ha->more_proc) {
+        /* more information: 2. about physical devices */
+        size = sprintf(buffer+len,"\nPhysical Devices:");
         len += size;  pos = begin + len;
- 
-        if (pos < offset) {
-            len = 0;
-            begin = pos;
-        }
-        if (pos > offset + length)
+        flag = FALSE;
+            
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
             goto stop_output;
+        for (i = 0; i < ha->bus_cnt; ++i) {
+            /* 2.a statistics (and retries/reassigns) */
+            TRACE2(("pdr_statistics() chn %d\n",i));                
+            pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_IOCTL;
+            gdtcmd.u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
+            gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4;
+            gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
+            gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
+            pds->bid = ha->raw[i].local_no;
+            pds->first = 0;
+            pds->entries = ha->raw[i].pdev_cnt;
+            cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
+                sizeof(pds->list[0]);
+            if (pds->entries > cnt)
+                pds->entries = cnt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, &gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status != S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            if (scp->SCp.Status != S_OK) 
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            if (scp.SCp.Status != S_OK) 
+#endif
+            { 
+                pds->count = 0;
+            }
 
-        if (ha->more_proc) {
-            /* more information: 1. about controller */
-            size = sprintf(buffer+len,
-                           " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
-                           ha->binfo.ser_no, ha->binfo.memsize / 1024);
-            len += size;  pos = begin + len;
-
-            /* 2. about physical devices */
-            size = sprintf(buffer+len,"\nPhysical Devices:");
-            len += size;  pos = begin + len;
-            flag = FALSE;
-            
-            buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
-            if (!buf) 
-                goto stop_output;
-            for (i = 0; i < ha->bus_cnt; ++i) {
-                /* 2.a statistics (and retries/reassigns) */
-                TRACE2(("pdr_statistics() chn %d\n",i));                
-                pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
+            /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
+            for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
+                /* 2.b drive info */
+                TRACE2(("scsi_drv_info() chn %d dev %d\n",
+                    i, ha->raw[i].id_list[j]));             
+                pdi = (gdth_diskinfo_str *)buf;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_IOCTL;
-                gdtcmd.u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
-                gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4;
-                gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
-                gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
-                pds->bid = ha->raw[i].local_no;
-                pds->first = 0;
-                pds->entries = ha->raw[i].pdev_cnt;
-                cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
-                    sizeof(pds->list[0]);
-                if (pds->entries > cnt)
-                    pds->entries = cnt;
-#if LINUX_VERSION_CODE >= 0x020503
+                gdtcmd.u.ioctl.p_param = paddr;
+                gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str);
+                gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
+                gdtcmd.u.ioctl.channel = 
+                    ha->raw[i].address | ha->raw[i].id_list[j];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
                 gdth_do_req(scp, &gdtcmd, cmnd, 30);
-                if (scp->sr_command->SCp.Status != S_OK) 
-#elif LINUX_VERSION_CODE >= 0x020322
+                if (scp->sr_command->SCp.Status == S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                if (scp->SCp.Status != S_OK) 
+                if (scp->SCp.Status == S_OK) 
 #else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                if (scp.SCp.Status != S_OK) 
+                if (scp.SCp.Status == S_OK) 
 #endif
-                { 
-                    pds->count = 0;
+                {
+                    strncpy(hrec,pdi->vendor,8);
+                    strncpy(hrec+8,pdi->product,16);
+                    strncpy(hrec+24,pdi->revision,4);
+                    hrec[28] = 0;
+                    size = sprintf(buffer+len,
+                                   "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
+                                   'A'+i,pdi->target_id,pdi->lun,hrec);
+                    len += size;  pos = begin + len;
+                    flag = TRUE;
+                    pdi->no_ldrive &= 0xffff;
+                    if (pdi->no_ldrive == 0xffff)
+                        strcpy(hrec,"--");
+                    else
+                        sprintf(hrec,"%d",pdi->no_ldrive);
+                    size = sprintf(buffer+len,
+                                   " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
+                                   pdi->blkcnt/(1024*1024/pdi->blksize),
+                                   hrec);
+                    len += size;  pos = begin + len;
+                } else {
+                    pdi->devtype = 0xff;
                 }
-
-                /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
-                for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
-                    /* 2.b drive info */
-                    TRACE2(("scsi_drv_info() chn %d dev %d\n",
-                        i, ha->raw[i].id_list[j]));             
-                    pdi = (gdth_diskinfo_str *)buf;
-                    gdtcmd.Service = CACHESERVICE;
-                    gdtcmd.OpCode = GDT_IOCTL;
-                    gdtcmd.u.ioctl.p_param = paddr;
-                    gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str);
-                    gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
-                    gdtcmd.u.ioctl.channel = 
-                        ha->raw[i].address | ha->raw[i].id_list[j];
-#if LINUX_VERSION_CODE >= 0x020503
-                    gdth_do_req(scp, &gdtcmd, cmnd, 30);
-                    if (scp->sr_command->SCp.Status == S_OK) 
-#elif LINUX_VERSION_CODE >= 0x020322
-                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                    if (scp->SCp.Status == S_OK) 
-#else
-                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                    if (scp.SCp.Status == S_OK) 
-#endif
-                    {
-                        strncpy(hrec,pdi->vendor,8);
-                        strncpy(hrec+8,pdi->product,16);
-                        strncpy(hrec+24,pdi->revision,4);
-                        hrec[28] = 0;
-                        size = sprintf(buffer+len,
-                                       "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
-                                       'A'+i,pdi->target_id,pdi->lun,hrec);
-                        len += size;  pos = begin + len;
-                        flag = TRUE;
-                        pdi->no_ldrive &= 0xffff;
-                        if (pdi->no_ldrive == 0xffff)
-                            strcpy(hrec,"--");
-                        else
-                            sprintf(hrec,"%d",pdi->no_ldrive);
-                        size = sprintf(buffer+len,
-                                       " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
-                                       pdi->blkcnt/(1024*1024/pdi->blksize),
-                                       hrec);
-                        len += size;  pos = begin + len;
-                    } else {
-                        pdi->devtype = 0xff;
-                    }
                     
-                    if (pdi->devtype == 0) {
-                        /* search retries/reassigns */
-                        for (k = 0; k < pds->count; ++k) {
-                            if (pds->list[k].tid == pdi->target_id &&
-                                pds->list[k].lun == pdi->lun) {
-                                size = sprintf(buffer+len,
-                                               " Retries:      \t%-6d    \tReassigns:     \t%d\n",
-                                               pds->list[k].retries,
-                                               pds->list[k].reassigns);
-                                len += size;  pos = begin + len;
-                                break;
-                            }
-                        }
-                        /* 2.c grown defects */
-                        TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
-                                i, ha->raw[i].id_list[j]));             
-                        pdef = (gdth_defcnt_str *)buf;
-                        gdtcmd.Service = CACHESERVICE;
-                        gdtcmd.OpCode = GDT_IOCTL;
-                        gdtcmd.u.ioctl.p_param = paddr;
-                        gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str);
-                        gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
-                        gdtcmd.u.ioctl.channel = 
-                            ha->raw[i].address | ha->raw[i].id_list[j];
-                        pdef->sddc_type = 0x08;
-#if LINUX_VERSION_CODE >= 0x020503
-                        gdth_do_req(scp, &gdtcmd, cmnd, 30);
-                        if (scp->sr_command->SCp.Status == S_OK) 
-#elif LINUX_VERSION_CODE >= 0x020322
-                        gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                        if (scp->SCp.Status == S_OK) 
-#else
-                        gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                        if (scp.SCp.Status == S_OK) 
-#endif
-                        {
+                if (pdi->devtype == 0) {
+                    /* search retries/reassigns */
+                    for (k = 0; k < pds->count; ++k) {
+                        if (pds->list[k].tid == pdi->target_id &&
+                            pds->list[k].lun == pdi->lun) {
                             size = sprintf(buffer+len,
-                                           " Grown Defects:\t%d\n",
-                                           pdef->sddc_cnt);
+                                           " Retries:      \t%-6d    \tReassigns:     \t%d\n",
+                                           pds->list[k].retries,
+                                           pds->list[k].reassigns);
                             len += size;  pos = begin + len;
+                            break;
                         }
                     }
-                    if (pos < offset) {
-                        len = 0;
-                        begin = pos;
-                    }
-                    if (pos > offset + length)
-                        goto stop_output;
-                }
-            }
-            gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
-
-            if (!flag) {
-                size = sprintf(buffer+len, "\n --\n");
-                len += size;  pos = begin + len;
-            }
-
-            /* 3. about logical drives */
-            size = sprintf(buffer+len,"\nLogical Drives:");
-            len += size;  pos = begin + len;
-            flag = FALSE;
-
-            buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
-            if (!buf) 
-                goto stop_output;
-            for (i = 0; i < MAX_LDRIVES; ++i) {
-                if (!ha->hdr[i].is_logdrv)
-                    continue;
-                drv_no = i;
-                j = k = 0;
-                is_mirr = FALSE;
-                do {
-                    /* 3.a log. drive info */
-                    TRACE2(("cache_drv_info() drive no %d\n",drv_no));
-                    pcdi = (gdth_cdrinfo_str *)buf;
+                    /* 2.c grown defects */
+                    TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
+                            i, ha->raw[i].id_list[j]));             
+                    pdef = (gdth_defcnt_str *)buf;
                     gdtcmd.Service = CACHESERVICE;
                     gdtcmd.OpCode = GDT_IOCTL;
                     gdtcmd.u.ioctl.p_param = paddr;
-                    gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
-                    gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
-                    gdtcmd.u.ioctl.channel = drv_no;
-#if LINUX_VERSION_CODE >= 0x020503
+                    gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str);
+                    gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
+                    gdtcmd.u.ioctl.channel = 
+                        ha->raw[i].address | ha->raw[i].id_list[j];
+                    pdef->sddc_type = 0x08;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
                     gdth_do_req(scp, &gdtcmd, cmnd, 30);
-                    if (scp->sr_command->SCp.Status != S_OK) 
-#elif LINUX_VERSION_CODE >= 0x020322
+                    if (scp->sr_command->SCp.Status == S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                     gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                    if (scp->SCp.Status != S_OK)
+                    if (scp->SCp.Status == S_OK) 
 #else
                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                    if (scp.SCp.Status != S_OK)
+                    if (scp.SCp.Status == S_OK) 
 #endif
                     {
-                        break;
-                    }
-                    pcdi->ld_dtype >>= 16;
-                    j++;
-                    if (pcdi->ld_dtype > 2) {
-                        strcpy(hrec, "missing");
-                    } else if (pcdi->ld_error & 1) {
-                        strcpy(hrec, "fault");
-                    } else if (pcdi->ld_error & 2) {
-                        strcpy(hrec, "invalid");
-                        k++; j--;
-                    } else {
-                        strcpy(hrec, "ok");
-                    }
-                    
-                    if (drv_no == i) {
-                        size = sprintf(buffer+len,
-                                       "\n Number:       \t%-2d        \tStatus:        \t%s\n",
-                                       drv_no, hrec);
-                        len += size;  pos = begin + len;
-                        flag = TRUE;
-                        no_mdrv = pcdi->cd_ldcnt;
-                        if (no_mdrv > 1 || pcdi->ld_slave != -1) {
-                            is_mirr = TRUE;
-                            strcpy(hrec, "RAID-1");
-                        } else if (pcdi->ld_dtype == 0) {
-                            strcpy(hrec, "Disk");
-                        } else if (pcdi->ld_dtype == 1) {
-                            strcpy(hrec, "RAID-0");
-                        } else if (pcdi->ld_dtype == 2) {
-                            strcpy(hrec, "Chain");
-                        } else {
-                            strcpy(hrec, "???");
-                        }
-                        size = sprintf(buffer+len,
-                                       " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
-                                       pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
-                                       hrec);
-                        len += size;  pos = begin + len;
-                    } else {
                         size = sprintf(buffer+len,
-                                       " Slave Number: \t%-2d        \tStatus:        \t%s\n",
-                                       drv_no & 0x7fff, hrec);
+                                       " Grown Defects:\t%d\n",
+                                       pdef->sddc_cnt);
                         len += size;  pos = begin + len;
                     }
-                    drv_no = pcdi->ld_slave;
-                    if (pos < offset) {
-                        len = 0;
-                        begin = pos;
-                    }
-                    if (pos > offset + length)
-                        goto stop_output;
-                } while (drv_no != -1);
-                
-                if (is_mirr) {
-                    size = sprintf(buffer+len,
-                                   " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
-                                   no_mdrv - j - k, k);
-                    len += size;  pos = begin + len;
                 }
-                
-                if (!ha->hdr[i].is_arraydrv)
-                    strcpy(hrec, "--");
-                else
-                    sprintf(hrec, "%d", ha->hdr[i].master_no);
-                size = sprintf(buffer+len,
-                               " To Array Drv.:\t%s\n", hrec);
-                len += size;  pos = begin + len;
                 if (pos < offset) {
                     len = 0;
                     begin = pos;
                 }
                 if (pos > offset + length)
                     goto stop_output;
-            }       
-            gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
-        
-            if (!flag) {
-                size = sprintf(buffer+len, "\n --\n");
-                len += size;  pos = begin + len;
-            }   
+            }
+        }
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
 
-            /* 4. about array drives */
-            size = sprintf(buffer+len,"\nArray Drives:");
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
             len += size;  pos = begin + len;
-            flag = FALSE;
+        }
 
-            buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
-            if (!buf) 
-                goto stop_output;
-            for (i = 0; i < MAX_LDRIVES; ++i) {
-                if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
-                    continue;
-                /* 4.a array drive info */
-                TRACE2(("array_info() drive no %d\n",i));
-                pai = (gdth_arrayinf_str *)buf;
+        /* 3. about logical drives */
+        size = sprintf(buffer+len,"\nLogical Drives:");
+        len += size;  pos = begin + len;
+        flag = FALSE;
+
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!ha->hdr[i].is_logdrv)
+                continue;
+            drv_no = i;
+            j = k = 0;
+            is_mirr = FALSE;
+            do {
+                /* 3.a log. drive info */
+                TRACE2(("cache_drv_info() drive no %d\n",drv_no));
+                pcdi = (gdth_cdrinfo_str *)buf;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_IOCTL;
                 gdtcmd.u.ioctl.p_param = paddr;
-                gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
-                gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
-                gdtcmd.u.ioctl.channel = i;
-#if LINUX_VERSION_CODE >= 0x020503
+                gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
+                gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
+                gdtcmd.u.ioctl.channel = drv_no;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
                 gdth_do_req(scp, &gdtcmd, cmnd, 30);
-                if (scp->sr_command->SCp.Status == S_OK) 
-#elif LINUX_VERSION_CODE >= 0x020322
+                if (scp->sr_command->SCp.Status != S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                if (scp->SCp.Status == S_OK) 
+                if (scp->SCp.Status != S_OK)
 #else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                if (scp.SCp.Status == S_OK) 
+                if (scp.SCp.Status != S_OK)
 #endif
                 {
-                    if (pai->ai_state == 0)
-                        strcpy(hrec, "idle");
-                    else if (pai->ai_state == 2)
-                        strcpy(hrec, "build");
-                    else if (pai->ai_state == 4)
-                        strcpy(hrec, "ready");
-                    else if (pai->ai_state == 6)
-                        strcpy(hrec, "fail");
-                    else if (pai->ai_state == 8 || pai->ai_state == 10)
-                        strcpy(hrec, "rebuild");
-                    else
-                        strcpy(hrec, "error");
-                    if (pai->ai_ext_state & 0x10)
-                        strcat(hrec, "/expand");
-                    else if (pai->ai_ext_state & 0x1)
-                        strcat(hrec, "/patch");
+                    break;
+                }
+                pcdi->ld_dtype >>= 16;
+                j++;
+                if (pcdi->ld_dtype > 2) {
+                    strcpy(hrec, "missing");
+                } else if (pcdi->ld_error & 1) {
+                    strcpy(hrec, "fault");
+                } else if (pcdi->ld_error & 2) {
+                    strcpy(hrec, "invalid");
+                    k++; j--;
+                } else {
+                    strcpy(hrec, "ok");
+                }
+                    
+                if (drv_no == i) {
                     size = sprintf(buffer+len,
                                    "\n Number:       \t%-2d        \tStatus:        \t%s\n",
-                                   i,hrec);
+                                   drv_no, hrec);
                     len += size;  pos = begin + len;
                     flag = TRUE;
-
-                    if (pai->ai_type == 0)
+                    no_mdrv = pcdi->cd_ldcnt;
+                    if (no_mdrv > 1 || pcdi->ld_slave != -1) {
+                        is_mirr = TRUE;
+                        strcpy(hrec, "RAID-1");
+                    } else if (pcdi->ld_dtype == 0) {
+                        strcpy(hrec, "Disk");
+                    } else if (pcdi->ld_dtype == 1) {
                         strcpy(hrec, "RAID-0");
-                    else if (pai->ai_type == 4)
-                        strcpy(hrec, "RAID-4");
-                    else if (pai->ai_type == 5)
-                        strcpy(hrec, "RAID-5");
-                    else 
-                        strcpy(hrec, "RAID-10");
+                    } else if (pcdi->ld_dtype == 2) {
+                        strcpy(hrec, "Chain");
+                    } else {
+                        strcpy(hrec, "???");
+                    }
                     size = sprintf(buffer+len,
                                    " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
-                                   pai->ai_size/(1024*1024/pai->ai_secsize),
+                                   pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
                                    hrec);
                     len += size;  pos = begin + len;
-                    if (pos < offset) {
-                        len = 0;
-                        begin = pos;
-                    }
-                    if (pos > offset + length)
-                        goto stop_output;
+                } else {
+                    size = sprintf(buffer+len,
+                                   " Slave Number: \t%-2d        \tStatus:        \t%s\n",
+                                   drv_no & 0x7fff, hrec);
+                    len += size;  pos = begin + len;
                 }
-            }
-            gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
-        
-            if (!flag) {
-                size = sprintf(buffer+len, "\n --\n");
+                drv_no = pcdi->ld_slave;
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
+            } while (drv_no != -1);
+             
+            if (is_mirr) {
+                size = sprintf(buffer+len,
+                               " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
+                               no_mdrv - j - k, k);
                 len += size;  pos = begin + len;
             }
-
-            /* 5. about host drives */
-            size = sprintf(buffer+len,"\nHost Drives:");
+              
+            if (!ha->hdr[i].is_arraydrv)
+                strcpy(hrec, "--");
+            else
+                sprintf(hrec, "%d", ha->hdr[i].master_no);
+            size = sprintf(buffer+len,
+                           " To Array Drv.:\t%s\n", hrec);
             len += size;  pos = begin + len;
-            flag = FALSE;
-
-            buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
-            if (!buf) 
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
                 goto stop_output;
-            for (i = 0; i < MAX_LDRIVES; ++i) {
-                if (!ha->hdr[i].is_logdrv || 
-                    (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
-                    continue;
-                /* 5.a get host drive list */
-                TRACE2(("host_get() drv_no %d\n",i));           
-                phg = (gdth_hget_str *)buf;
-                gdtcmd.Service = CACHESERVICE;
-                gdtcmd.OpCode = GDT_IOCTL;
-                gdtcmd.u.ioctl.p_param = paddr;
-                gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str);
-                gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
-                gdtcmd.u.ioctl.channel = i;
-                phg->entries = MAX_HDRIVES;
-                phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
-#if LINUX_VERSION_CODE >= 0x020503
-                gdth_do_req(scp, &gdtcmd, cmnd, 30);
-                if (scp->sr_command->SCp.Status != S_OK) 
-#elif LINUX_VERSION_CODE >= 0x020322
-                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                if (scp->SCp.Status != S_OK) 
+        }       
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+        
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
+        }   
+
+        /* 4. about array drives */
+        size = sprintf(buffer+len,"\nArray Drives:");
+        len += size;  pos = begin + len;
+        flag = FALSE;
+
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
+                continue;
+            /* 4.a array drive info */
+            TRACE2(("array_info() drive no %d\n",i));
+            pai = (gdth_arrayinf_str *)buf;
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_IOCTL;
+            gdtcmd.u.ioctl.p_param = paddr;
+            gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
+            gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
+            gdtcmd.u.ioctl.channel = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, &gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status == S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            if (scp->SCp.Status == S_OK) 
 #else
-                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                if (scp.SCp.Status != S_OK) 
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            if (scp.SCp.Status == S_OK) 
 #endif
-                {
-                    ha->hdr[i].ldr_no = i;
-                    ha->hdr[i].rw_attribs = 0;
-                    ha->hdr[i].start_sec = 0;
-                } else {
-                    for (j = 0; j < phg->entries; ++j) {
-                        k = phg->entry[j].host_drive;
-                        if (k >= MAX_LDRIVES)
-                            continue;
-                        ha->hdr[k].ldr_no = phg->entry[j].log_drive;
-                        ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
-                        ha->hdr[k].start_sec = phg->entry[j].start_sec;
-                    }
-                }
-            }
-            gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
-
-            for (i = 0; i < MAX_HDRIVES; ++i) {
-                if (!(ha->hdr[i].present))
-                    continue;
-                
+            {
+                if (pai->ai_state == 0)
+                    strcpy(hrec, "idle");
+                else if (pai->ai_state == 2)
+                    strcpy(hrec, "build");
+                else if (pai->ai_state == 4)
+                    strcpy(hrec, "ready");
+                else if (pai->ai_state == 6)
+                    strcpy(hrec, "fail");
+                else if (pai->ai_state == 8 || pai->ai_state == 10)
+                    strcpy(hrec, "rebuild");
+                else
+                    strcpy(hrec, "error");
+                if (pai->ai_ext_state & 0x10)
+                    strcat(hrec, "/expand");
+                else if (pai->ai_ext_state & 0x1)
+                    strcat(hrec, "/patch");
                 size = sprintf(buffer+len,
-                               "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
-                               i, ha->hdr[i].ldr_no);
+                               "\n Number:       \t%-2d        \tStatus:        \t%s\n",
+                               i,hrec);
                 len += size;  pos = begin + len;
                 flag = TRUE;
 
+                if (pai->ai_type == 0)
+                    strcpy(hrec, "RAID-0");
+                else if (pai->ai_type == 4)
+                    strcpy(hrec, "RAID-4");
+                else if (pai->ai_type == 5)
+                    strcpy(hrec, "RAID-5");
+                else 
+                    strcpy(hrec, "RAID-10");
                 size = sprintf(buffer+len,
-                               " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
-                               ha->hdr[i].size/2048, ha->hdr[i].start_sec);
+                               " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
+                               pai->ai_size/(1024*1024/pai->ai_secsize),
+                               hrec);
                 len += size;  pos = begin + len;
                 if (pos < offset) {
                     len = 0;
@@ -1299,60 +708,125 @@
                 if (pos > offset + length)
                     goto stop_output;
             }
+        }
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
         
-            if (!flag) {
-                size = sprintf(buffer+len, "\n --\n");
-                len += size;  pos = begin + len;
-            }
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
         }
 
-        /* controller events */
-        size = sprintf(buffer+len,"\nController Events:\n");
+        /* 5. about host drives */
+        size = sprintf(buffer+len,"\nHost Drives:");
         len += size;  pos = begin + len;
+        flag = FALSE;
 
-        for (id = -1;;) {
-            id = gdth_read_event(ha, id, &estr);
-            if (estr.event_source == 0)
-                break;
-            if (estr.event_data.eu.driver.ionode == hanum &&
-                estr.event_source == ES_ASYNC) { 
-                gdth_log_event(&estr.event_data, hrec);
-                do_gettimeofday(&tv);
-                sec = (int)(tv.tv_sec - estr.first_stamp);
-                if (sec < 0) sec = 0;
-                size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
-                               sec/3600, sec%3600/60, sec%60, hrec);
-                len += size;  pos = begin + len;
-                if (pos < offset) {
-                    len = 0;
-                    begin = pos;
+        buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!ha->hdr[i].is_logdrv || 
+                (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
+                continue;
+            /* 5.a get host drive list */
+            TRACE2(("host_get() drv_no %d\n",i));           
+            phg = (gdth_hget_str *)buf;
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_IOCTL;
+            gdtcmd.u.ioctl.p_param = paddr;
+            gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str);
+            gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
+            gdtcmd.u.ioctl.channel = i;
+            phg->entries = MAX_HDRIVES;
+            phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, &gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status != S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            if (scp->SCp.Status != S_OK) 
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            if (scp.SCp.Status != S_OK) 
+#endif
+            {
+                ha->hdr[i].ldr_no = i;
+                ha->hdr[i].rw_attribs = 0;
+                ha->hdr[i].start_sec = 0;
+            } else {
+                for (j = 0; j < phg->entries; ++j) {
+                    k = phg->entry[j].host_drive;
+                    if (k >= MAX_LDRIVES)
+                        continue;
+                    ha->hdr[k].ldr_no = phg->entry[j].log_drive;
+                    ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
+                    ha->hdr[k].start_sec = phg->entry[j].start_sec;
                 }
-                if (pos > offset + length)
-                    goto stop_output;
             }
-            if (id == -1)
-                break;
         }
-#ifdef GDTH_IOCTL_PROC
-    } else {
-        gdth_iord_str *piord;
+        gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
 
-        /* request from tool (GDTMON,..) */
-        piord = (gdth_iord_str *)ha->pscratch;
-        if (piord == NULL)
-            goto stop_output;
-        length = piord->size;
-        memcpy(buffer+len, (char *)piord, length);
-        gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr);
-        len = length; 
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (!(ha->hdr[i].present))
+                continue;
+              
+            size = sprintf(buffer+len,
+                           "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
+                           i, ha->hdr[i].ldr_no);
+            len += size;  pos = begin + len;
+            flag = TRUE;
+
+            size = sprintf(buffer+len,
+                           " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
+                           (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
+            len += size;  pos = begin + len;
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+        }
+        
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
+        }
+    }
+
+    /* controller events */
+    size = sprintf(buffer+len,"\nController Events:\n");
+    len += size;  pos = begin + len;
+
+    for (id = -1;;) {
+        id = gdth_read_event(ha, id, &estr);
+        if (estr.event_source == 0)
+            break;
+        if (estr.event_data.eu.driver.ionode == hanum &&
+            estr.event_source == ES_ASYNC) { 
+            gdth_log_event(&estr.event_data, hrec);
+            do_gettimeofday(&tv);
+            sec = (int)(tv.tv_sec - estr.first_stamp);
+            if (sec < 0) sec = 0;
+            size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
+                           sec/3600, sec%3600/60, sec%60, hrec);
+            len += size;  pos = begin + len;
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+        }
+        if (id == -1)
+            break;
     }
-#endif
 
 stop_output:
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     scsi_release_request(scp);
     scsi_free_host_dev(sdev);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     scsi_release_command(scp);
     scsi_free_host_dev(sdev);
 #endif
@@ -1365,7 +839,8 @@
     return(len);
 }
 
-#if LINUX_VERSION_CODE >= 0x020503
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 static void gdth_do_req(Scsi_Request *scp, gdth_cmd_str *gdtcmd, 
                         char *cmnd, int timeout)
 {
@@ -1389,9 +864,9 @@
                         char *cmnd, int timeout)
 {
     unsigned bufflen;
-#if LINUX_VERSION_CODE >= 0x020407
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
     DECLARE_COMPLETION(wait);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     DECLARE_MUTEX_LOCKED(sem);
 #else
     struct semaphore sem = MUTEX_LOCKED;
@@ -1405,19 +880,19 @@
         scp->SCp.this_residual = DEFAULT_PRI;
         bufflen = 0;
     }
-#if LINUX_VERSION_CODE >= 0x020407
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
     scp->request.rq_status = RQ_SCSI_BUSY;
     scp->request.waiting = &wait;
     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
     wait_for_completion(&wait);
 #else
     scp->request.sem = &sem;
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
 #else
-    GDTH_LOCK_SCSI_DOCMD();
+    spin_lock_irq(&io_request_lock);
     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
-    GDTH_UNLOCK_SCSI_DOCMD();
+    spin_unlock_irq(&io_request_lock);
 #endif
     down(&sem);
 #endif
@@ -1428,11 +903,11 @@
 {
     TRACE2(("gdth_scsi_done()\n"));
 
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     scp->request->rq_status = RQ_SCSI_DONE;
     if (scp->request->waiting != NULL)
         complete(scp->request->waiting);
-#elif LINUX_VERSION_CODE >= 0x020407
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
     scp->request.rq_status = RQ_SCSI_DONE;
     if (scp->request.waiting != NULL)
         complete(scp->request.waiting);
@@ -1444,7 +919,7 @@
 }
 
 static char *gdth_ioctl_alloc(int hanum, int size, int scratch, 
-                              ulong32 *paddr)
+                              ulong64 *paddr)
 {
     gdth_ha_str *ha;
     ulong flags;
@@ -1463,11 +938,11 @@
     } else if (scratch) {
         ret_val = NULL;
     } else {
-#if LINUX_VERSION_CODE >= 0x020400
-	dma_addr_t dma_addr;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        dma_addr_t dma_addr;
 
         ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr);
-	*paddr = (ulong32)dma_addr;
+        *paddr = dma_addr;
 #else
         ret_val = scsi_init_malloc(size, GFP_ATOMIC | GFP_DMA);
         if (ret_val)
@@ -1479,7 +954,7 @@
     return ret_val;
 }
 
-static void gdth_ioctl_free(int hanum, int size, char *buf, ulong32 paddr)
+static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
 {
     gdth_ha_str *ha;
     ulong flags;
@@ -1490,7 +965,7 @@
     if (buf == ha->pscratch) {
         ha->scratch_busy = FALSE;
     } else {
-#if LINUX_VERSION_CODE >= 0x020400
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
         pci_free_consistent(ha->pdev, size, buf, paddr);
 #else
         scsi_init_free((void *)buf, size);
@@ -1533,7 +1008,7 @@
 
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         scp = ha->cmd_tab[i].cmnd;
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
         t = scp->device->id;
 #else
@@ -1546,14 +1021,10 @@
             GDTH_UNLOCK_HA(ha, flags);
             while (!scp->SCp.have_data_in)
                 barrier();
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
             GDTH_LOCK_SCSI_DONE(scp->device->host, flags);
             scp->scsi_done(scp);
             GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags);
-#elif LINUX_VERSION_CODE >= 0x020503
-            GDTH_LOCK_SCSI_DONE(scp->host, flags);
-            scp->scsi_done(scp);
-            GDTH_UNLOCK_SCSI_DONE(scp->host, flags);
 #else
             GDTH_LOCK_SCSI_DONE(flags);
             scp->scsi_done(scp);
@@ -1576,7 +1047,7 @@
     GDTH_LOCK_HA(ha, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
         t = scp->device->id;
 #else
@@ -1602,7 +1073,7 @@
     GDTH_LOCK_HA(ha, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-#if LINUX_VERSION_CODE >= 0x02053C
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
         t = scp->device->id;
 #else
@@ -1624,7 +1095,6 @@
     oldto = scp->timeout_per_command;
     scp->timeout_per_command = timeout;
 
-#if LINUX_VERSION_CODE >= 0x02014B
     if (timeout == 0) {
         del_timer(&scp->eh_timeout);
         scp->eh_timeout.data = (unsigned long) NULL;
@@ -1636,17 +1106,6 @@
         scp->eh_timeout.expires = jiffies + timeout;
         add_timer(&scp->eh_timeout);
     }
-#else
-    if (timeout > 0) {
-        if (timer_table[SCSI_TIMER].expires == 0) {
-            timer_table[SCSI_TIMER].expires = jiffies + timeout;
-            timer_active |= 1 << SCSI_TIMER;
-        } else {
-            if (jiffies + timeout < timer_table[SCSI_TIMER].expires)
-                timer_table[SCSI_TIMER].expires = jiffies + timeout;
-        }
-    }
-#endif
 
     return oldto;
 }
--- diff/drivers/scsi/gdth_proc.h	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/gdth_proc.h	2004-05-27 18:34:18.000000000 +0100
@@ -2,42 +2,31 @@
 #define _GDTH_PROC_H
 
 /* gdth_proc.h 
- * $Id: gdth_proc.h,v 1.14 2003/08/27 11:37:35 achim Exp $
+ * $Id: gdth_proc.h,v 1.16 2004/01/14 13:09:01 achim Exp $
  */
 
-static int gdth_set_info(char *buffer,int length,int hanum,int busnum);
-static int gdth_get_info(char *buffer,char **start,off_t offset,
-                         int length,int hanum,int busnum);
+static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
+                         int hanum,int busnum);
+static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
+                         struct Scsi_Host *host,int hanum,int busnum);
 
-#if LINUX_VERSION_CODE >= 0x020503
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 static void gdth_do_req(Scsi_Request *srp, gdth_cmd_str *cmd, 
                         char *cmnd, int timeout);
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp);
-#ifdef GDTH_IOCTL_PROC
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Request *scp);
-#endif
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
                         char *cmnd, int timeout);
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
-#ifdef GDTH_IOCTL_PROC
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
-#endif
 #else 
 static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
                         char *cmnd, int timeout);
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
-#ifdef GDTH_IOCTL_PROC
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
-#endif
 #endif
 
 static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
-                              ulong32 *paddr);  
-static void gdth_ioctl_free(int hanum, int size, char *buf, ulong32 paddr);
-#ifdef GDTH_IOCTL_PROC
-static int gdth_ioctl_check_bin(int hanum, ushort size);
-#endif
+                              ulong64 *paddr);  
+static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr);
 static void gdth_wait_completion(int hanum, int busnum, int id);
 static void gdth_stop_timeout(int hanum, int busnum, int id);
 static void gdth_start_timeout(int hanum, int busnum, int id);
--- diff/drivers/scsi/ipr.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/scsi/ipr.c	2004-05-27 18:34:18.000000000 +0100
@@ -406,7 +406,7 @@
 	trace_entry->type = type;
 	trace_entry->cmd_index = ipr_cmd->cmd_index;
 	trace_entry->res_handle = ipr_cmd->ioarcb.res_handle;
-	trace_entry->add_data = add_data;
+	trace_entry->u.add_data = add_data;
 }
 #else
 #define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0)
@@ -447,7 +447,7 @@
 static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
 {
 	ipr_reinit_ipr_cmnd(ipr_cmd);
-	ipr_cmd->scratch = 0;
+	ipr_cmd->u.scratch = 0;
 	init_timer(&ipr_cmd->timer);
 }
 
@@ -676,8 +676,8 @@
  **/
 static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd)
 {
-	if (ipr_cmd->sibling)
-		ipr_cmd->sibling = NULL;
+	if (ipr_cmd->u.sibling)
+		ipr_cmd->u.sibling = NULL;
 	else
 		complete(&ipr_cmd->completion);
 }
@@ -729,20 +729,20 @@
 		list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
 		list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_pending_q);
 
-		ipr_cmd->hostrcb = hostrcb;
+		ipr_cmd->u.hostrcb = hostrcb;
 		ioarcb = &ipr_cmd->ioarcb;
 
 		ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
 		ioarcb->cmd_pkt.request_type = IPR_RQTYPE_HCAM;
 		ioarcb->cmd_pkt.cdb[0] = IPR_HOST_CONTROLLED_ASYNC;
 		ioarcb->cmd_pkt.cdb[1] = type;
-		ioarcb->cmd_pkt.cdb[7] = (IPR_HOSTRCB_SZ >> 8) & 0xff;
-		ioarcb->cmd_pkt.cdb[8] = IPR_HOSTRCB_SZ & 0xff;
+		ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff;
+		ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff;
 
-		ioarcb->read_data_transfer_length = cpu_to_be32(IPR_HOSTRCB_SZ);
+		ioarcb->read_data_transfer_length = cpu_to_be32(sizeof(hostrcb->hcam));
 		ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
 		ipr_cmd->ioadl[0].flags_and_data_len =
-			cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | IPR_HOSTRCB_SZ);
+			cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(hostrcb->hcam));
 		ipr_cmd->ioadl[0].address = cpu_to_be32(hostrcb->hostrcb_dma);
 
 		if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE)
@@ -794,7 +794,7 @@
 	struct ipr_config_table_entry *cfgte;
 	u32 is_ndn = 1;
 
-	cfgte = &hostrcb->ccn.cfgte;
+	cfgte = &hostrcb->hcam.u.ccn.cfgte;
 
 	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
 		if (!memcmp(&res->cfgte.res_addr, &cfgte->res_addr,
@@ -822,7 +822,7 @@
 
 	memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry));
 
-	if (hostrcb->notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) {
+	if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) {
 		if (res->sdev) {
 			res->sdev->hostdata = NULL;
 			res->del_from_ml = 1;
@@ -852,7 +852,7 @@
 static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
 {
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-	struct ipr_hostrcb *hostrcb = ipr_cmd->hostrcb;
+	struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
 	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
 
 	list_del(&hostrcb->queue);
@@ -902,7 +902,8 @@
 static void ipr_log_cache_error(struct ipr_ioa_cfg *ioa_cfg,
 				struct ipr_hostrcb *hostrcb)
 {
-	struct ipr_hostrcb_type_02_error *error = &hostrcb->error.type_02_error;
+	struct ipr_hostrcb_type_02_error *error =
+		&hostrcb->hcam.u.error.u.type_02_error;
 
 	ipr_err("-----Current Configuration-----\n");
 	ipr_err("Cache Directory Card Information:\n");
@@ -937,14 +938,15 @@
 {
 	int errors_logged, i;
 	struct ipr_hostrcb_device_data_entry *dev_entry;
+	struct ipr_hostrcb_type_03_error *error;
 
-	errors_logged = be32_to_cpu(hostrcb->error.type_03_error.errors_logged);
+	error = &hostrcb->hcam.u.error.u.type_03_error;
+	errors_logged = be32_to_cpu(error->errors_logged);
 
 	ipr_err("Device Errors Detected/Logged: %d/%d\n",
-		be32_to_cpu(hostrcb->error.type_03_error.errors_detected),
-		errors_logged);
+		be32_to_cpu(error->errors_detected), errors_logged);
 
-	dev_entry = hostrcb->error.type_03_error.dev_entry;
+	dev_entry = error->dev_entry;
 
 	for (i = 0; i < errors_logged; i++, dev_entry++) {
 		ipr_err_separator;
@@ -996,7 +998,7 @@
 
 	memset(zero_sn, '0', IPR_SERIAL_NUM_LEN);
 
-	error = &hostrcb->error.type_04_error;
+	error = &hostrcb->hcam.u.error.u.type_04_error;
 
 	ipr_err_separator;
 
@@ -1064,7 +1066,7 @@
 				  struct ipr_hostrcb *hostrcb)
 {
 	int i;
-	int ioa_data_len = be32_to_cpu(hostrcb->length);
+	int ioa_data_len = be32_to_cpu(hostrcb->hcam.length);
 
 	if (ioa_data_len == 0)
 		return;
@@ -1074,10 +1076,10 @@
 
 	for (i = 0; i < ioa_data_len / 4; i += 4) {
 		ipr_err("%08X: %08X %08X %08X %08X\n", i*4,
-			be32_to_cpu(hostrcb->raw.data[i]),
-			be32_to_cpu(hostrcb->raw.data[i+1]),
-			be32_to_cpu(hostrcb->raw.data[i+2]),
-			be32_to_cpu(hostrcb->raw.data[i+3]));
+			be32_to_cpu(hostrcb->hcam.u.raw.data[i]),
+			be32_to_cpu(hostrcb->hcam.u.raw.data[i+1]),
+			be32_to_cpu(hostrcb->hcam.u.raw.data[i+2]),
+			be32_to_cpu(hostrcb->hcam.u.raw.data[i+3]));
 	}
 }
 
@@ -1119,19 +1121,19 @@
 	u32 ioasc;
 	int error_index;
 
-	if (hostrcb->notify_type != IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY)
+	if (hostrcb->hcam.notify_type != IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY)
 		return;
 
-	if (hostrcb->notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST)
+	if (hostrcb->hcam.notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST)
 		dev_err(&ioa_cfg->pdev->dev, "Error notifications lost\n");
 
-	ioasc = be32_to_cpu(hostrcb->error.failing_dev_ioasc);
+	ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
 
 	if (ioasc == IPR_IOASC_BUS_WAS_RESET ||
 	    ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER) {
 		/* Tell the midlayer we had a bus reset so it will handle the UA properly */
 		scsi_report_bus_reset(ioa_cfg->host,
-				      hostrcb->error.failing_dev_res_addr.bus);
+				      hostrcb->hcam.u.error.failing_dev_res_addr.bus);
 	}
 
 	error_index = ipr_get_error(ioasc);
@@ -1139,8 +1141,8 @@
 	if (!ipr_error_table[error_index].log_hcam)
 		return;
 
-	if (ipr_is_device(&hostrcb->error.failing_dev_res_addr)) {
-		ipr_res_err(ioa_cfg, hostrcb->error.failing_dev_res_addr,
+	if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {
+		ipr_res_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,
 			    "%s\n", ipr_error_table[error_index].error);
 	} else {
 		dev_err(&ioa_cfg->pdev->dev, "%s\n",
@@ -1153,7 +1155,7 @@
 	if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
 		return;
 
-	switch (hostrcb->overlay_id) {
+	switch (hostrcb->hcam.overlay_id) {
 	case IPR_HOST_RCB_OVERLAY_ID_1:
 		ipr_log_generic_error(ioa_cfg, hostrcb);
 		break;
@@ -1173,7 +1175,7 @@
 	default:
 		dev_err(&ioa_cfg->pdev->dev,
 			"Unknown error received. Overlay ID: %d\n",
-			hostrcb->overlay_id);
+			hostrcb->hcam.overlay_id);
 		break;
 	}
 }
@@ -1192,7 +1194,7 @@
 static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
 {
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-	struct ipr_hostrcb *hostrcb = ipr_cmd->hostrcb;
+	struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
 	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
 
 	list_del(&hostrcb->queue);
@@ -2972,6 +2974,7 @@
 	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
 	cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
 
+	ipr_sdev_err(scsi_cmd->device, "Resetting device\n");
 	ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
 
 	ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
@@ -3011,10 +3014,10 @@
 	 * If abort has not completed, indicate the reset has, else call the
 	 * abort's done function to wake the sleeping eh thread
 	 */
-	if (ipr_cmd->sibling->sibling)
-		ipr_cmd->sibling->sibling = NULL;
+	if (ipr_cmd->u.sibling->u.sibling)
+		ipr_cmd->u.sibling->u.sibling = NULL;
 	else
-		ipr_cmd->sibling->done(ipr_cmd->sibling);
+		ipr_cmd->u.sibling->done(ipr_cmd->u.sibling);
 
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 	LEAVE;
@@ -3045,9 +3048,10 @@
 		return;
 	}
 
+	ipr_sdev_err(ipr_cmd->u.sdev, "Abort timed out. Resetting bus\n");
 	reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
-	ipr_cmd->sibling = reset_cmd;
-	reset_cmd->sibling = ipr_cmd;
+	ipr_cmd->u.sibling = reset_cmd;
+	reset_cmd->u.sibling = ipr_cmd;
 	reset_cmd->ioarcb.res_handle = ipr_cmd->ioarcb.res_handle;
 	cmd_pkt = &reset_cmd->ioarcb.cmd_pkt;
 	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
@@ -3106,7 +3110,9 @@
 	cmd_pkt->cdb[3] = (ioarcb_addr >> 16) & 0xff;
 	cmd_pkt->cdb[4] = (ioarcb_addr >> 8) & 0xff;
 	cmd_pkt->cdb[5] = ioarcb_addr & 0xff;
+	ipr_cmd->u.sdev = scsi_cmd->device;
 
+	ipr_sdev_err(scsi_cmd->device, "Aborting command: %02X\n", scsi_cmd->cmnd[0]);
 	ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_ABORT_TASK_TIMEOUT);
 	ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
 
@@ -3175,6 +3181,7 @@
 		writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.clr_interrupt_reg);
 		int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
 
+		list_del(&ioa_cfg->reset_cmd->queue);
 		del_timer(&ioa_cfg->reset_cmd->timer);
 		ipr_reset_ioa_job(ioa_cfg->reset_cmd);
 	} else {
@@ -3570,12 +3577,12 @@
 	ipr_sdev_err(ipr_cmd->scsi_cmd->device, "%s\n",
 		     ipr_error_table[error_index].error);
 
-	if ((ioasa->gpdd.device_end_state <= ARRAY_SIZE(ipr_gpdd_dev_end_states)) &&
-	    (ioasa->gpdd.device_bus_phase <= ARRAY_SIZE(ipr_gpdd_dev_bus_phases))) {
+	if ((ioasa->u.gpdd.end_state <= ARRAY_SIZE(ipr_gpdd_dev_end_states)) &&
+	    (ioasa->u.gpdd.bus_phase <=  ARRAY_SIZE(ipr_gpdd_dev_bus_phases))) {
 		ipr_sdev_err(ipr_cmd->scsi_cmd->device,
 			     "Device End state: %s Phase: %s\n",
-			     ipr_gpdd_dev_end_states[ioasa->gpdd.device_end_state],
-			     ipr_gpdd_dev_bus_phases[ioasa->gpdd.device_bus_phase]);
+			     ipr_gpdd_dev_end_states[ioasa->u.gpdd.end_state],
+			     ipr_gpdd_dev_bus_phases[ioasa->u.gpdd.bus_phase]);
 	}
 
 	if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len))
@@ -3619,7 +3626,7 @@
 
 	if (ipr_is_vset_device(res) &&
 	    ioasc == IPR_IOASC_MED_DO_NOT_REALLOC &&
-	    ioasa->vset.failing_lba_hi != 0) {
+	    ioasa->u.vset.failing_lba_hi != 0) {
 		sense_buf[0] = 0x72;
 		sense_buf[1] = IPR_IOASC_SENSE_KEY(ioasc);
 		sense_buf[2] = IPR_IOASC_SENSE_CODE(ioasc);
@@ -3630,14 +3637,14 @@
 		sense_buf[9] = 0x0A;
 		sense_buf[10] = 0x80;
 
-		failing_lba = be32_to_cpu(ioasa->vset.failing_lba_hi);
+		failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_hi);
 
 		sense_buf[12] = (failing_lba & 0xff000000) >> 24;
 		sense_buf[13] = (failing_lba & 0x00ff0000) >> 16;
 		sense_buf[14] = (failing_lba & 0x0000ff00) >> 8;
 		sense_buf[15] = failing_lba & 0x000000ff;
 
-		failing_lba = be32_to_cpu(ioasa->vset.failing_lba_lo);
+		failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo);
 
 		sense_buf[16] = (failing_lba & 0xff000000) >> 24;
 		sense_buf[17] = (failing_lba & 0x00ff0000) >> 16;
@@ -3669,9 +3676,9 @@
 		} else {
 			if (ioasc == IPR_IOASC_MED_DO_NOT_REALLOC) {
 				if (ipr_is_vset_device(res))
-					failing_lba = be32_to_cpu(ioasa->vset.failing_lba_lo);
+					failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo);
 				else
-					failing_lba = be32_to_cpu(ioasa->dasd.failing_lba);
+					failing_lba = be32_to_cpu(ioasa->u.dasd.failing_lba);
 
 				sense_buf[0] |= 0x80;	/* Or in the Valid bit */
 				sense_buf[3] = (failing_lba & 0xff000000) >> 24;
@@ -4118,7 +4125,7 @@
 	struct ipr_supported_device *supp_dev = &ioa_cfg->vpd_cbs->supp_dev;
 	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
 	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
-	struct ipr_resource_entry *res = ipr_cmd->res;
+	struct ipr_resource_entry *res = ipr_cmd->u.res;
 
 	ipr_cmd->job_step = ipr_ioa_reset_done;
 
@@ -4126,7 +4133,7 @@
 		if (!ipr_is_af_dasd_device(res))
 			continue;
 
-		ipr_cmd->res = res;
+		ipr_cmd->u.res = res;
 		ipr_set_sup_dev_dflt(supp_dev, &res->cfgte.std_inq_data.vpids);
 
 		ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
@@ -4367,8 +4374,8 @@
 			      length);
 
 	ipr_cmd->job_step = ipr_set_supported_devs;
-	ipr_cmd->res = list_entry(ioa_cfg->used_res_q.next,
-				  struct ipr_resource_entry, queue);
+	ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next,
+				    struct ipr_resource_entry, queue);
 
 	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
 
@@ -4802,6 +4809,7 @@
 	ipr_cmd->timer.expires = jiffies + IPR_OPERATIONAL_TIMEOUT;
 	ipr_cmd->timer.function = (void (*)(unsigned long))ipr_timeout;
 	add_timer(&ipr_cmd->timer);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
 
 	LEAVE;
 	return IPR_RC_JOB_RETURN;
@@ -4886,12 +4894,12 @@
 	hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next,
 			     struct ipr_hostrcb, queue);
 	list_del(&hostrcb->queue);
-	memset(hostrcb, 0, IPR_HOSTRCB_SZ);
+	memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam));
 
 	rc = ipr_get_ldump_data_section(ioa_cfg,
 					be32_to_cpu(sdt.entry[0].bar_str_offset),
-					(u32 *)hostrcb,
-					min(length, (int)IPR_HOSTRCB_SZ) / sizeof(u32));
+					(u32 *)&hostrcb->hcam,
+					min(length, (int)sizeof(hostrcb->hcam)) / sizeof(u32));
 
 	if (!rc)
 		ipr_handle_log_data(ioa_cfg, hostrcb);
@@ -5022,8 +5030,8 @@
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 	int rc = IPR_RC_JOB_RETURN;
 
-	if (!ipr_reset_allowed(ioa_cfg) && ipr_cmd->time_left) {
-		ipr_cmd->time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
+	if (!ipr_reset_allowed(ioa_cfg) && ipr_cmd->u.time_left) {
+		ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
 		ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
 	} else {
 		ipr_cmd->job_step = ipr_reset_start_bist;
@@ -5062,7 +5070,7 @@
 		ipr_cmd->job_step = ipr_reset_start_bist;
 	}
 
-	ipr_cmd->time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
+	ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
 	ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
 
 	LEAVE;
@@ -5148,7 +5156,7 @@
 static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd)
 {
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-	enum ipr_shutdown_type shutdown_type = ipr_cmd->shutdown_type;
+	enum ipr_shutdown_type shutdown_type = ipr_cmd->u.shutdown_type;
 	unsigned long timeout;
 	int rc = IPR_RC_JOB_CONTINUE;
 
@@ -5189,7 +5197,7 @@
 static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd)
 {
 	u32 rc, ioasc;
-	unsigned long scratch = ipr_cmd->scratch;
+	unsigned long scratch = ipr_cmd->u.scratch;
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 
 	do {
@@ -5215,7 +5223,7 @@
 		}
 
 		ipr_reinit_ipr_cmnd(ipr_cmd);
-		ipr_cmd->scratch = scratch;
+		ipr_cmd->u.scratch = scratch;
 		rc = ipr_cmd->job_step(ipr_cmd);
 	} while(rc == IPR_RC_JOB_CONTINUE);
 }
@@ -5247,7 +5255,7 @@
 	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
 	ioa_cfg->reset_cmd = ipr_cmd;
 	ipr_cmd->job_step = job_step;
-	ipr_cmd->shutdown_type = shutdown_type;
+	ipr_cmd->u.shutdown_type = shutdown_type;
 
 	ipr_reset_ioa_job(ipr_cmd);
 }
@@ -5531,7 +5539,8 @@
 			goto cleanup;
 
 		memset(ioa_cfg->hostrcb[i], 0, sizeof(struct ipr_hostrcb));
-		ioa_cfg->hostrcb[i]->hostrcb_dma = ioa_cfg->hostrcb_dma[i];
+		ioa_cfg->hostrcb[i]->hostrcb_dma =
+			ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam);
 		list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q);
 	}
 
--- diff/drivers/scsi/ipr.h	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/scsi/ipr.h	2004-05-27 18:34:18.000000000 +0100
@@ -36,8 +36,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.0.6"
-#define IPR_DRIVER_DATE "(May 3, 2004)"
+#define IPR_DRIVER_VERSION "2.0.7"
+#define IPR_DRIVER_DATE "(May 21, 2004)"
 
 /*
  * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing
@@ -413,8 +413,8 @@
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioasa_gpdd {
-	u8 device_end_state;
-	u8 device_bus_phase;
+	u8 end_state;
+	u8 bus_phase;
 	u16 reserved;
 	u32 ioa_data[23];
 }__attribute__((packed, aligned (4)));
@@ -457,7 +457,7 @@
 		struct ipr_ioasa_af_dasd dasd;
 		struct ipr_ioasa_gpdd gpdd;
 		struct ipr_ioasa_raw raw;
-	};
+	} u;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_mode_parm_hdr {
@@ -617,14 +617,14 @@
 		struct ipr_hostrcb_type_02_error type_02_error;
 		struct ipr_hostrcb_type_03_error type_03_error;
 		struct ipr_hostrcb_type_04_error type_04_error;
-	};
+	} u;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_raw {
 	u32 data[sizeof(struct ipr_hostrcb_error)/sizeof(u32)];
 }__attribute__((packed, aligned (4)));
 
-struct ipr_hostrcb {
+struct ipr_hcam {
 	u8 op_code;
 #define IPR_HOST_RCB_OP_CODE_CONFIG_CHANGE			0xE1
 #define IPR_HOST_RCB_OP_CODE_LOG_DATA				0xE2
@@ -662,14 +662,14 @@
 		struct ipr_hostrcb_error error;
 		struct ipr_hostrcb_cfg_ch_not ccn;
 		struct ipr_hostrcb_raw raw;
-	};
+	} u;
+}__attribute__((packed, aligned (4)));
 
-	/* Driver added data */
+struct ipr_hostrcb {
+	struct ipr_hcam hcam;
 	u32 hostrcb_dma;
 	struct list_head queue;
-}__attribute__((packed, aligned (4)));
-
-#define IPR_HOSTRCB_SZ offsetof(struct ipr_hostrcb, hostrcb_dma)
+};
 
 /* IPR smart dump table structures */
 struct ipr_sdt_entry {
@@ -785,7 +785,7 @@
 		u32 ioasc;
 		u32 add_data;
 		u32 res_addr;
-	};
+	} u;
 };
 
 struct ipr_sglist {
@@ -939,7 +939,8 @@
 		unsigned long scratch;
 		struct ipr_resource_entry *res;
 		struct ipr_cmnd *sibling;
-	};
+		struct scsi_device *sdev;
+	} u;
 
 	struct ipr_ioa_cfg *ioa_cfg;
 };
--- diff/drivers/scsi/megaraid.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/scsi/megaraid.c	2004-05-27 18:34:18.000000000 +0100
@@ -4612,6 +4612,26 @@
 	pci_dev_func = pdev->devfn;
 
 	/*
+	 * The megaraid3 stuff reports the ID of the Intel part which is not
+	 * remotely specific to the megaraid
+	 */
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+		u16 magic;
+		/*
+		 * Don't fall over the Compaq management cards using the same
+		 * PCI identifier
+		 */
+		if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ &&
+		    pdev->subsystem_device == 0xC000)
+		   	return -ENODEV;
+		/* Now check the magic signature byte */
+		pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
+		if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE)
+			return -ENODEV;
+		/* Ok it is probably a megaraid */
+	}
+
+	/*
 	 * For these vendor and device ids, signature offsets are not
 	 * valid and 64 bit is implicit
 	 */
--- diff/drivers/scsi/nsp32.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/scsi/nsp32.c	2004-05-27 18:34:18.000000000 +0100
@@ -38,7 +38,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ctype.h>
-#include <linux/interrupt.h>
 
 #include <asm/dma.h>
 #include <asm/system.h>
--- diff/drivers/scsi/qla1280.c	2004-05-27 13:41:20.000000000 +0100
+++ source/drivers/scsi/qla1280.c	2004-05-27 18:34:18.000000000 +0100
@@ -3119,6 +3119,7 @@
  * Returns:
  *      0 = success, was able to issue command.
  */
+#ifdef QLA_64BIT_PTR
 static int
 qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 {
@@ -3381,9 +3382,8 @@
 
 	return status;
 }
+#else /* !QLA_64BIT_PTR */
 
-
-#ifndef QLA_64BIT_PTR
 /*
  * qla1280_32bit_start_scsi
  *      The start SCSI is responsible for building request packets on
--- diff/drivers/scsi/qlogicfas408.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/scsi/qlogicfas408.c	2004-05-27 18:34:18.000000000 +0100
@@ -538,7 +538,7 @@
  *	Return info string
  */
 
-char *qlogicfas408_info(struct Scsi_Host *host)
+const char *qlogicfas408_info(struct Scsi_Host *host)
 {
 	struct qlogicfas408_priv *priv = get_priv_by_host(host);
 	return priv->qinfo;
--- diff/drivers/scsi/qlogicfas408.h	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/scsi/qlogicfas408.h	2004-05-27 18:34:18.000000000 +0100
@@ -111,7 +111,7 @@
 int qlogicfas408_bus_reset(Scsi_Cmnd * cmd);
 int qlogicfas408_host_reset(Scsi_Cmnd * cmd);
 int qlogicfas408_device_reset(Scsi_Cmnd * cmd);
-char *qlogicfas408_info(struct Scsi_Host *host);
+const char *qlogicfas408_info(struct Scsi_Host *host);
 int qlogicfas408_get_chip_type(int qbase, int int_type);
 void qlogicfas408_setup(int qbase, int id, int int_type);
 int qlogicfas408_detect(int qbase, int int_type);
--- diff/drivers/scsi/scsi_lib.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsi_lib.c	2004-05-27 18:34:18.000000000 +0100
@@ -951,6 +951,22 @@
 	return BLKPREP_KILL;
 }
 
+static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
+			       sector_t *error_sector)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct scsi_driver *drv;
+
+	if (sdev->sdev_state != SDEV_RUNNING)
+		return -ENXIO;
+
+	drv = *(struct scsi_driver **) disk->private_data;
+	if (drv->issue_flush)
+		return drv->issue_flush(&sdev->sdev_gendev, error_sector);
+
+	return -EOPNOTSUPP;
+}
+
 static int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
 	struct scsi_device *sdev = q->queuedata;
@@ -1332,7 +1348,8 @@
 	blk_queue_max_sectors(q, shost->max_sectors);
 	blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
 	blk_queue_segment_boundary(q, shost->dma_boundary);
- 
+	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+
 	if (!shost->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 	return q;
@@ -1610,7 +1627,9 @@
 
 	case SDEV_CANCEL:
 		switch (oldstate) {
+		case SDEV_CREATED:
 		case SDEV_RUNNING:
+		case SDEV_OFFLINE:
 			break;
 		default:
 			goto illegal;
@@ -1619,9 +1638,7 @@
 
 	case SDEV_DEL:
 		switch (oldstate) {
-		case SDEV_CREATED:
 		case SDEV_CANCEL:
-		case SDEV_OFFLINE:
 			break;
 		default:
 			goto illegal;
--- diff/drivers/scsi/scsi_logging.h	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsi_logging.h	2004-05-27 18:34:18.000000000 +0100
@@ -46,7 +46,7 @@
 
 #define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)		\
 {								\
-        if ((SCSI_LOG_LEVEL(SHIFT, BITS)) > (LEVEL))		\
+        if (unlikely((SCSI_LOG_LEVEL(SHIFT, BITS)) > (LEVEL)))	\
 		(CMD);						\
 }
 #else
--- diff/drivers/scsi/scsi_scan.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/scsi/scsi_scan.c	2004-05-27 18:34:18.000000000 +0100
@@ -80,7 +80,6 @@
 MODULE_PARM_DESC(max_luns,
 		 "last scsi LUN (should be between 1 and 2^32-1)");
 
-#ifdef CONFIG_SCSI_REPORT_LUNS
 /*
  * max_scsi_report_luns: the maximum number of LUNS that will be
  * returned from the REPORT LUNS command. 8 times this value must
@@ -88,13 +87,19 @@
  * in practice, the maximum number of LUNs suppored by any device
  * is about 16k.
  */
-static unsigned int max_scsi_report_luns = 128;
+static unsigned int max_scsi_report_luns = 511;
 
 module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(max_report_luns,
 		 "REPORT LUNS maximum number of LUNS received (should be"
 		 " between 1 and 16384)");
-#endif
+
+static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;
+
+module_param_named(inq_timeout, scsi_inq_timeout, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(inq_timeout, 
+		 "Timeout (in seconds) waiting for devices to answer INQUIRY."
+		 " Default is 5. Some non-compliant devices need more.");
 
 /**
  * scsi_unlock_floptical - unlock device via a special MODE SENSE command
@@ -212,6 +217,11 @@
 	INIT_LIST_HEAD(&sdev->starved_entry);
 	spin_lock_init(&sdev->list_lock);
 
+
+	/* if the device needs this changing, it may do so in the
+	 * slave_configure function */
+	sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;
+
 	/*
 	 * Some low level driver could use device->type
 	 */
@@ -346,7 +356,7 @@
 
 	memset(inq_result, 0, 36);
 	scsi_wait_req(sreq, (void *) scsi_cmd, (void *) inq_result, 36,
-		      SCSI_TIMEOUT + 4 * HZ, 3);
+		      HZ/2 + HZ*scsi_inq_timeout, 3);
 
 	SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: 1st INQUIRY %s with"
 			" code 0x%x\n", sreq->sr_result ?
@@ -400,7 +410,7 @@
 		memset(inq_result, 0, possible_inq_resp_len);
 		scsi_wait_req(sreq, (void *) scsi_cmd,
 			      (void *) inq_result,
-			      possible_inq_resp_len, SCSI_TIMEOUT + 4 * HZ, 3);
+			      possible_inq_resp_len, (1+scsi_inq_timeout)*(HZ/2), 3);
 		SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: 2nd INQUIRY"
 				" %s with code 0x%x\n", sreq->sr_result ?
 				"failed" : "successful", sreq->sr_result));
@@ -628,10 +638,6 @@
 		spin_unlock_irqrestore(sdev->host->host_lock, flags);
 	}
 
-	/* if the device needs this changing, it may do so in the detect
-	 * function */
-	sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;
-
 	sdev->use_10_for_rw = 1;
 
 	if (*bflags & BLIST_MS_SKIP_PAGE_08)
@@ -863,7 +869,6 @@
 			return;
 }
 
-#ifdef CONFIG_SCSI_REPORT_LUNS
 /**
  * scsilun_to_int: convert a scsi_lun to an int
  * @scsilun:	struct scsi_lun to be converted.
@@ -924,9 +929,14 @@
 	u8 *data;
 
 	/*
-	 * Only support SCSI-3 and up devices.
-	 */
-	if (sdev->scsi_level < SCSI_3)
+	 * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
+	 * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
+	 * support more than 8 LUNs.
+	 */
+	if ((bflags & BLIST_NOREPORTLUN) || 
+	     sdev->scsi_level < SCSI_2 ||
+	    (sdev->scsi_level < SCSI_3 && 
+	     (!(bflags & BLIST_REPORTLUN2) || sdev->host->max_lun <= 8)) )
 		return 1;
 	if (bflags & BLIST_NOLUN)
 		return 0;
@@ -1090,9 +1100,6 @@
 	printk(ALLOC_FAILURE_MSG, __FUNCTION__);
 	return 0;
 }
-#else
-# define scsi_report_lun_scan(sdev, blags, rescan)	(1)
-#endif	/* CONFIG_SCSI_REPORT_LUNS */
 
 struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
 				    uint channel, uint id, uint lun)
--- diff/drivers/scsi/scsiiom.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsiiom.c	2004-05-27 18:34:18.000000000 +0100
@@ -15,7 +15,7 @@
 };
 
 
-UCHAR
+static UCHAR
 dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
     UCHAR cmd; UCHAR  disc_allowed, try_sync_nego;
@@ -227,7 +227,7 @@
 #if DMA_INT
     UCHAR  dstatus;
 #endif
-    DC390_AFLAGS DC390_IFLAGS; //DC390_DFLAGS
+    DC390_IFLAGS;
 
     pACB = (PACB)dev_id;
     for (pACB2 = dc390_pACB_start; (pACB2 && pACB2 != pACB); pACB2 = pACB2->pNextACB);
@@ -237,26 +237,21 @@
 	return IRQ_NONE;
     }
     
-    //DC390_LOCK_DRV;
-
     sstatus = DC390_read8 (Scsi_Status);
     if( !(sstatus & INTERRUPT) )
-	{ /*DC390_UNLOCK_DRV;*/ return IRQ_NONE; };
+	return IRQ_NONE;
 
     DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus));
 
 #if DMA_INT
     DC390_LOCK_IO(pACB->pScsiHost);
-    DC390_LOCK_ACB;
     dstatus = dc390_dma_intr (pACB);
-    DC390_UNLOCK_ACB;
     DC390_UNLOCK_IO(pACB->pScsiHost);
 
     DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus));
     if (! (dstatus & SCSI_INTERRUPT))
       {
 	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"));
-	//DC390_UNLOCK_DRV;
 	return IRQ_NONE;
       };
 #else
@@ -266,8 +261,6 @@
 #endif
 
     DC390_LOCK_IO(pACB->pScsiHost);
-    DC390_LOCK_ACB;
-    //DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */
 
     istate = DC390_read8 (Intern_State);
     istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
@@ -339,14 +332,11 @@
     }
 
  unlock:
-    //DC390_LOCK_DRV_NI;
-    DC390_UNLOCK_ACB;
     DC390_UNLOCK_IO(pACB->pScsiHost);
-    //DC390_UNLOCK_DRV; /* Restore initial flags */
     return IRQ_HANDLED;
 }
 
-irqreturn_t do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
 {
     irqreturn_t ret;
     DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq));
@@ -356,7 +346,7 @@
     return ret;
 }
 
-void
+static void
 dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     UCHAR   sstatus;
@@ -410,7 +400,7 @@
     }	    
 }
 
-void
+static void
 dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     UCHAR   sstatus, residual, bval;
@@ -521,7 +511,7 @@
     {
 	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
 	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
-    }	    
+    }
 }
 
 static void
@@ -740,9 +730,9 @@
 	psgl = pSRB->pSegmentList;
 	//dc390_pci_sync(pSRB);
 
-	while (pSRB->TotalXferredLen + (ULONG) psgl->length < pSRB->Saved_Ptr)
+	while (pSRB->TotalXferredLen + (ULONG) sg_dma_len(psgl) < pSRB->Saved_Ptr)
 	{
-	    pSRB->TotalXferredLen += (ULONG) psgl->length;
+	    pSRB->TotalXferredLen += (ULONG) sg_dma_len(psgl);
 	    pSRB->SGIndex++;
 	    if( pSRB->SGIndex < pSRB->SGcount )
 	    {
@@ -762,7 +752,7 @@
     } else if(pcmd->request_buffer) {
 	//dc390_pci_sync(pSRB);
 
-	pSRB->Segmentx.length = pcmd->request_bufflen - pSRB->Saved_Ptr;
+	sg_dma_len(&pSRB->Segmentx) = pcmd->request_bufflen - pSRB->Saved_Ptr;
 	pSRB->SGcount = 1;
 	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
     } else {
@@ -873,7 +863,7 @@
 }
 
 
-void
+static void
 dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
 {
     PSGL   psgl;
@@ -885,6 +875,8 @@
 	if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n",
 			  pDCB->TargetID, pDCB->TargetLUN);
 	else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n");
+
+	pSRB->pSRBDCB = pDCB;
 	dc390_EnableMsgOut_Abort (pACB, pSRB);
 	if (pDCB) pDCB->DCBFlag |= ABORT_DEV;
 	return;
@@ -1150,7 +1142,6 @@
 	    pSRB = psrb;
 	}
 	pDCB->pGoingSRB = 0;
-	dc390_Query_to_Waiting (pACB);
 	dc390_Waiting_process (pACB);
     }
     else
@@ -1466,7 +1457,7 @@
 		ptr2 = pSRB->pSegmentList;
 		for( i=pSRB->SGIndex; i < bval; i++)
 		{
-		    swlval += ptr2->length;
+		    swlval += sg_dma_len(ptr2);
 		    ptr2++;
 		}
 		REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n",\
@@ -1619,20 +1610,15 @@
 	  pACB->scan_devices = 0;
      };
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30)
     pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen;
-#endif
 
     if (!DCB_removed) dc390_Going_remove (pDCB, pSRB);
     /* Add to free list */
     dc390_Free_insert (pACB, pSRB);
 
     DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid));
-    DC390_UNLOCK_ACB_NI;
     pcmd->scsi_done (pcmd);
-    DC390_LOCK_ACB_NI;
 
-    dc390_Query_to_Waiting (pACB);
     dc390_Waiting_process (pACB);
     return;
 }
@@ -1668,9 +1654,7 @@
 /*	    ReleaseSRB( pDCB, pSRB ); */
 
 	    DEBUG0(printk (KERN_DEBUG "DC390: DoingSRB_Done: done pid %li\n", pcmd->pid));
-	    DC390_UNLOCK_ACB_NI;
 	    pcmd->scsi_done( pcmd );
-	    DC390_LOCK_ACB_NI;
 #endif	
 	    psrb  = psrb2;
 	}
@@ -1679,7 +1663,6 @@
 	pdcb->TagMask = 0;
 	pdcb = pdcb->pNextDCB;
     } while( pdcb != pDCB );
-    dc390_Query_to_Waiting (pACB);
 }
 
 
--- diff/drivers/scsi/sd.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/scsi/sd.c	2004-05-27 18:34:18.000000000 +0100
@@ -111,6 +111,7 @@
 static void sd_shutdown(struct device *dev);
 static void sd_rescan(struct device *);
 static int sd_init_command(struct scsi_cmnd *);
+static int sd_issue_flush(struct device *, sector_t *);
 static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
 		 struct scsi_request *SRpnt, unsigned char *buffer);
 
@@ -124,6 +125,7 @@
 	},
 	.rescan			= sd_rescan,
 	.init_command		= sd_init_command,
+	.issue_flush		= sd_issue_flush,
 };
 
 /* Device no to disk mapping:
@@ -673,6 +675,62 @@
 	return 1;
 }
 
+static int sd_sync_cache(struct scsi_device *sdp)
+{
+	struct scsi_request *sreq;
+	int retries, res;
+
+	if (!scsi_device_online(sdp))
+		return -ENODEV;
+
+	sreq = scsi_allocate_request(sdp, GFP_KERNEL);
+	if (!sreq) {
+		printk("FAILED\n  No memory for request\n");
+		return -ENOMEM;
+	}
+
+	sreq->sr_data_direction = DMA_NONE;
+	for (retries = 3; retries > 0; --retries) {
+		unsigned char cmd[10] = { 0 };
+
+		cmd[0] = SYNCHRONIZE_CACHE;
+		/*
+		 * Leave the rest of the command zero to indicate
+		 * flush everything.
+		 */
+		scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
+		if (sreq->sr_result == 0)
+			break;
+	}
+
+	res = sreq->sr_result;
+	if (res) {
+		printk(KERN_WARNING "FAILED\n  status = %x, message = %02x, "
+				    "host = %d, driver = %02x\n  ",
+				    status_byte(res), msg_byte(res),
+				    host_byte(res), driver_byte(res));
+			if (driver_byte(res) & DRIVER_SENSE)
+				print_req_sense("sd", sreq);
+	}
+
+	scsi_release_request(sreq);
+	return res;
+}
+
+static int sd_issue_flush(struct device *dev, sector_t *error_sector)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	struct scsi_disk *sdkp = dev_get_drvdata(dev);
+
+	if (!sdkp)
+               return -ENODEV;
+
+	if (!sdkp->WCE)
+		return 0;
+
+	return sd_sync_cache(sdp);
+}
+
 static void sd_rescan(struct device *dev)
 {
 	struct scsi_disk *sdkp = dev_get_drvdata(dev);
@@ -1500,52 +1558,17 @@
 static void sd_shutdown(struct device *dev)
 {
 	struct scsi_device *sdp = to_scsi_device(dev);
-	struct scsi_disk *sdkp;
-	struct scsi_request *sreq;
-	int retries, res;
+	struct scsi_disk *sdkp = dev_get_drvdata(dev);
 
-	sdkp = dev_get_drvdata(dev);
 	if (!sdkp)
                return;         /* this can happen */
 
-	if (!scsi_device_online(sdp) || !sdkp->WCE)
+	if (!sdkp->WCE)
 		return;
 
-	printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: ",
+	printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
 			sdkp->disk->disk_name);
-
-	sreq = scsi_allocate_request(sdp, GFP_KERNEL);
-	if (!sreq) {
-		printk("FAILED\n  No memory for request\n");
-		return;
-	}
-
-	sreq->sr_data_direction = DMA_NONE;
-	for (retries = 3; retries > 0; --retries) {
-		unsigned char cmd[10] = { 0 };
-
-		cmd[0] = SYNCHRONIZE_CACHE;
-		/*
-		 * Leave the rest of the command zero to indicate
-		 * flush everything.
-		 */
-		scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
-		if (sreq->sr_result == 0)
-			break;
-	}
-
-	res = sreq->sr_result;
-	if (res) {
-		printk(KERN_WARNING "FAILED\n  status = %x, message = %02x, "
-				    "host = %d, driver = %02x\n  ",
-				    status_byte(res), msg_byte(res),
-				    host_byte(res), driver_byte(res));
-			if (driver_byte(res) & DRIVER_SENSE)
-				print_req_sense("sd", sreq);
-	}
-	
-	scsi_release_request(sreq);
-	printk("\n");
+	sd_sync_cache(sdp);
 }	
 
 /**
--- diff/drivers/scsi/sg.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/scsi/sg.c	2004-05-27 18:34:18.000000000 +0100
@@ -7,7 +7,7 @@
  * Original driver (sg.c):
  *        Copyright (C) 1992 Lawrence Foard
  * Version 2 and 3 extensions to driver:
- *        Copyright (C) 1998 - 2002 Douglas Gilbert
+ *        Copyright (C) 1998 - 2004 Douglas Gilbert
  *
  *  Modified  19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Devfs support
  *
@@ -17,27 +17,18 @@
  * any later version.
  *
  */
-#include <linux/config.h>
-static int sg_version_num = 30530;	/* 2 digits for each component */
+
+static int sg_version_num = 30531;	/* 2 digits for each component */
+#define SG_VERSION_STR "3.5.31"
+
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
  *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
  *        (otherwise the macros compile to empty statements).
- *        Then before running the program to be debugged enter:
- *          # echo "scsi log timeout 7" > /proc/scsi/scsi
- *        This will send copious output to the console and the log which
- *        is usually /var/log/messages. To turn off debugging enter:
- *          # echo "scsi log timeout 0" > /proc/scsi/scsi
- *        The 'timeout' token was chosen because it is relatively unused.
- *        The token 'hlcomplete' should be used but that triggers too
- *        much output from the sd device driver. To dump the current
- *        state of the SCSI mid level data structures enter:
- *          # echo "scsi dump 1" > /proc/scsi/scsi
- *        To dump the state of sg's data structures use:
- *          # cat /proc/scsi/sg/debug
  *
  */
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/fs.h>
@@ -69,7 +60,7 @@
 
 #ifdef CONFIG_SCSI_PROC_FS
 #include <linux/proc_fs.h>
-static char *sg_version_str = "3.5.30 [20040124]";
+static char *sg_version_date = "20040513";
 
 static int sg_proc_init(void);
 static void sg_proc_cleanup(void);
@@ -110,7 +101,7 @@
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
 
-#define SG_DEV_ARR_LUMP 6	/* amount to over allocate sg_dev_arr by */
+#define SG_DEV_ARR_LUMP 32	/* amount to over allocate sg_dev_arr by */
 
 static int sg_add(struct class_device *);
 static void sg_remove(struct class_device *);
@@ -1333,85 +1324,44 @@
 
 static int sg_sysfs_valid = 0;
 
-static int
-sg_add(struct class_device *cl_dev)
+static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
 {
-	struct scsi_device *scsidp = to_scsi_device(cl_dev->dev);
-	struct gendisk *disk;
-	Sg_device *sdp = NULL;
+	Sg_device *sdp;
 	unsigned long iflags;
-	struct cdev * cdev = NULL;
+	void *old_sg_dev_arr = NULL;
 	int k, error;
 
-	disk = alloc_disk(1);
-	if (!disk)
+	sdp = vmalloc(sizeof(Sg_device));
+	if (!sdp)
 		return -ENOMEM;
 
-	cdev = cdev_alloc();
-	if (! cdev)
-		return -ENOMEM;
 	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	if (sg_nr_dev >= sg_dev_max) {	/* try to resize */
+	if (unlikely(sg_nr_dev >= sg_dev_max)) {	/* try to resize */
 		Sg_device **tmp_da;
 		int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
-
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-		tmp_da = (Sg_device **)vmalloc(
-				tmp_dev_max * sizeof(Sg_device *));
-		if (NULL == tmp_da) {
-			printk(KERN_ERR
-			       "sg_add: device array cannot be resized\n");
-			error = -ENOMEM;
-			goto out;
-		}
+
+		tmp_da = vmalloc(tmp_dev_max * sizeof(Sg_device *));
+		if (unlikely(!tmp_da))
+			goto expand_failed;
+
 		write_lock_irqsave(&sg_dev_arr_lock, iflags);
-		memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
-		memcpy(tmp_da, sg_dev_arr,
-		       sg_dev_max * sizeof (Sg_device *));
-		vfree((char *) sg_dev_arr);
+		memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
+		memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *));
+		old_sg_dev_arr = sg_dev_arr;
 		sg_dev_arr = tmp_da;
 		sg_dev_max = tmp_dev_max;
 	}
 
-find_empty_slot:
 	for (k = 0; k < sg_dev_max; k++)
 		if (!sg_dev_arr[k])
 			break;
-	if (k >= SG_MAX_DEVS) {
-		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-		printk(KERN_WARNING
-		       "Unable to attach sg device <%d, %d, %d, %d>"
-		       " type=%d, minor number exceeds %d\n",
-		       scsidp->host->host_no, scsidp->channel, scsidp->id,
-		       scsidp->lun, scsidp->type, SG_MAX_DEVS - 1);
-		if (NULL != sdp)
-			vfree((char *) sdp);
-		error = -ENODEV;
-		goto out;
-	}
-	if (k < sg_dev_max) {
-		if (NULL == sdp) {
-			write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-			sdp = (Sg_device *)vmalloc(sizeof(Sg_device));
-			write_lock_irqsave(&sg_dev_arr_lock, iflags);
-			if (!sg_dev_arr[k])
-				goto find_empty_slot;
-		}
-	} else
-		sdp = NULL;
-	if (NULL == sdp) {
-		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-		printk(KERN_ERR "sg_add: Sg_device cannot be allocated\n");
-		error = -ENOMEM;
-		goto out;
-	}
+	if (unlikely(k >= SG_MAX_DEVS))
+		goto overflow;
 
-	SCSI_LOG_TIMEOUT(3, printk("sg_add: dev=%d \n", k));
 	memset(sdp, 0, sizeof(*sdp));
+	SCSI_LOG_TIMEOUT(3, printk("sg_alloc: dev=%d \n", k));
 	sprintf(disk->disk_name, "sg%d", k);
-	cdev->owner = THIS_MODULE;
-	cdev->ops = &sg_fops;
-	disk->major = SCSI_GENERIC_MAJOR;
 	disk->first_minor = k;
 	sdp->disk = disk;
 	sdp->device = scsidp;
@@ -1421,6 +1371,55 @@
 	sg_nr_dev++;
 	sg_dev_arr[k] = sdp;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	error = k;
+
+ out:
+	if (error < 0)
+		vfree(sdp);
+	vfree(old_sg_dev_arr);
+	return error;
+
+ expand_failed:
+	printk(KERN_ERR "sg_alloc: device array cannot be resized\n");
+	error = -ENOMEM;
+	goto out;
+
+ overflow:
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	printk(KERN_WARNING
+	       "Unable to attach sg device <%d, %d, %d, %d> type=%d, minor "
+	       "number exceeds %d\n", scsidp->host->host_no, scsidp->channel,
+	       scsidp->id, scsidp->lun, scsidp->type, SG_MAX_DEVS - 1);
+	error = -ENODEV;
+	goto out;
+}
+
+static int
+sg_add(struct class_device *cl_dev)
+{
+	struct scsi_device *scsidp = to_scsi_device(cl_dev->dev);
+	struct gendisk *disk;
+	Sg_device *sdp = NULL;
+	struct cdev * cdev = NULL;
+	int error, k;
+
+	disk = alloc_disk(1);
+	if (!disk)
+		return -ENOMEM;
+	disk->major = SCSI_GENERIC_MAJOR;
+
+	error = -ENOMEM;
+	cdev = cdev_alloc();
+	if (!cdev)
+		goto out;
+	cdev->owner = THIS_MODULE;
+	cdev->ops = &sg_fops;
+
+	error = sg_alloc(disk, scsidp);
+	if (error < 0)
+		goto out;
+	k = error;
+	sdp = sg_dev_arr[k];
 
 	devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k),
 			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
@@ -1543,6 +1542,7 @@
 MODULE_AUTHOR("Douglas Gilbert");
 MODULE_DESCRIPTION("SCSI generic (sg) driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(SG_VERSION_STR);
 
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
 MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
@@ -2844,7 +2844,8 @@
 
 static int sg_proc_seq_show_version(struct seq_file *s, void *v)
 {
-	seq_printf(s, "%d\t%s\n", sg_version_num, sg_version_str);
+	seq_printf(s, "%d\t%s [%s]\n", sg_version_num, SG_VERSION_STR,
+		   sg_version_date);
 	return 0;
 }
 
--- diff/drivers/scsi/sr_ioctl.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/sr_ioctl.c	2004-05-27 18:34:18.000000000 +0100
@@ -331,6 +331,9 @@
 	int result;
 	unsigned char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
 
+	if (!buffer)
+		return -ENOMEM;
+
 	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
 	cgc.timeout = IOCTL_TIMEOUT;
 
--- diff/drivers/scsi/st.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/scsi/st.c	2004-05-27 18:34:18.000000000 +0100
@@ -486,7 +486,7 @@
 		   tape_name(STp), forward ? "forward" : "backward"));
 
 	SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
-			   STp->timeout, MAX_RETRIES, TRUE);
+			   STp->device->timeout, MAX_RETRIES, TRUE);
 	if (!SRpnt)
 		return (STp->buffer)->syscall_result;
 
@@ -544,7 +544,7 @@
 		cmd[4] = blks;
 
 		SRpnt = st_do_scsi(NULL, STp, cmd, transfer, SCSI_DATA_WRITE,
-				   STp->timeout, MAX_WRITE_RETRIES, TRUE);
+				   STp->device->timeout, MAX_WRITE_RETRIES, TRUE);
 		if (!SRpnt)
 			return (STp->buffer)->syscall_result;
 
@@ -867,7 +867,7 @@
 		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
 		cmd[0] = READ_BLOCK_LIMITS;
 
-		SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->device->timeout,
 				   MAX_READY_RETRIES, TRUE);
 		if (!SRpnt) {
 			retval = (STp->buffer)->syscall_result;
@@ -894,7 +894,7 @@
 	cmd[0] = MODE_SENSE;
 	cmd[4] = 12;
 
-	SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->device->timeout,
 			   MAX_READY_RETRIES, TRUE);
 	if (!SRpnt) {
 		retval = (STp->buffer)->syscall_result;
@@ -1116,7 +1116,7 @@
 		cmd[4] = 1 + STp->two_fm;
 
 		SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
-				   STp->timeout, MAX_WRITE_RETRIES, TRUE);
+				   STp->device->timeout, MAX_WRITE_RETRIES, TRUE);
 		if (!SRpnt) {
 			result = (STp->buffer)->syscall_result;
 			goto out;
@@ -1509,7 +1509,7 @@
 		cmd[4] = blks;
 
 		SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
-				   STp->timeout, MAX_WRITE_RETRIES, !async_write);
+				   STp->device->timeout, MAX_WRITE_RETRIES, !async_write);
 		if (!SRpnt) {
 			retval = STbp->syscall_result;
 			goto out;
@@ -1679,7 +1679,7 @@
 
 	SRpnt = *aSRpnt;
 	SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, SCSI_DATA_READ,
-			   STp->timeout, MAX_RETRIES, TRUE);
+			   STp->device->timeout, MAX_RETRIES, TRUE);
 	release_buffering(STp);
 	*aSRpnt = SRpnt;
 	if (!SRpnt)
@@ -2081,7 +2081,7 @@
 			DEBC( printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name,
 			       (value & ~MT_ST_SET_LONG_TIMEOUT)));
 		} else {
-			STp->timeout = value * HZ;
+			STp->device->timeout = value * HZ;
 			DEBC( printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n",
 				name, value) );
 		}
@@ -2189,7 +2189,7 @@
 	cmd[4] = 255;
 
 	SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ,
-			   STp->timeout, 0, TRUE);
+			   STp->device->timeout, 0, TRUE);
 	if (SRpnt == NULL)
 		return (STp->buffer)->syscall_result;
 
@@ -2220,7 +2220,7 @@
 	(STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
 
 	SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
-			   (slow ? STp->long_timeout : STp->timeout), 0, TRUE);
+			   (slow ? STp->long_timeout : STp->device->timeout), 0, TRUE);
 	if (SRpnt == NULL)
 		return (STp->buffer)->syscall_result;
 
@@ -2332,7 +2332,7 @@
 	}
 	if (STp->immediate) {
 		cmd[1] = 1;	/* Don't wait for completion */
-		timeout = STp->timeout;
+		timeout = STp->device->timeout;
 	}
 	else
 		timeout = STp->long_timeout;
@@ -2512,7 +2512,7 @@
 		cmd[2] = (arg >> 16);
 		cmd[3] = (arg >> 8);
 		cmd[4] = arg;
-		timeout = STp->timeout;
+		timeout = STp->device->timeout;
                 DEBC(
                      if (cmd_in == MTWEOF)
                                printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name,
@@ -2530,7 +2530,7 @@
 		cmd[0] = REZERO_UNIT;
 		if (STp->immediate) {
 			cmd[1] = 1;	/* Don't wait for completion */
-			timeout = STp->timeout;
+			timeout = STp->device->timeout;
 		}
                 DEBC(printk(ST_DEB_MSG "%s: Rewinding tape.\n", name));
 		fileno = blkno = at_sm = 0;
@@ -2543,7 +2543,7 @@
 		cmd[0] = START_STOP;
 		if (STp->immediate) {
 			cmd[1] = 1;	/* Don't wait for completion */
-			timeout = STp->timeout;
+			timeout = STp->device->timeout;
 		}
 		cmd[4] = 3;
                 DEBC(printk(ST_DEB_MSG "%s: Retensioning tape.\n", name));
@@ -2576,7 +2576,7 @@
 		cmd[1] = (arg ? 1 : 0);	/* Long erase with non-zero argument */
 		if (STp->immediate) {
 			cmd[1] |= 2;	/* Don't wait for completion */
-			timeout = STp->timeout;
+			timeout = STp->device->timeout;
 		}
 		else
 			timeout = STp->long_timeout * 8;
@@ -2628,7 +2628,7 @@
 		(STp->buffer)->b_data[9] = (ltmp >> 16);
 		(STp->buffer)->b_data[10] = (ltmp >> 8);
 		(STp->buffer)->b_data[11] = ltmp;
-		timeout = STp->timeout;
+		timeout = STp->device->timeout;
                 DEBC(
 			if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
 				printk(ST_DEB_MSG
@@ -2809,7 +2809,7 @@
 		if (!logical && !STp->scsi2_logical)
 			scmd[1] = 1;
 	}
-	SRpnt = st_do_scsi(NULL, STp, scmd, 20, SCSI_DATA_READ, STp->timeout,
+	SRpnt = st_do_scsi(NULL, STp, scmd, 20, SCSI_DATA_READ, STp->device->timeout,
 			   MAX_READY_RETRIES, TRUE);
 	if (!SRpnt)
 		return (STp->buffer)->syscall_result;
@@ -2911,7 +2911,7 @@
 	}
 	if (STp->immediate) {
 		scmd[1] |= 1;		/* Don't wait for completion */
-		timeout = STp->timeout;
+		timeout = STp->device->timeout;
 	}
 
 	SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE,
@@ -3408,11 +3408,17 @@
 		goto out;
 	}
 	up(&STp->lock);
-	i = scsi_cmd_ioctl(STp->disk, cmd_in, arg);
-	if (i != -ENOTTY)
-		return i;
-	else
-		return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+	switch (cmd_in) {
+		case SCSI_IOCTL_GET_IDLUN:
+		case SCSI_IOCTL_GET_BUS_NUMBER:
+			break;
+		default:
+			i = scsi_cmd_ioctl(STp->disk, cmd_in, arg);
+			if (i != -ENOTTY)
+				return i;
+			break;
+	}
+	return scsi_ioctl(STp->device, cmd_in, (void *) arg);
 
  out:
 	up(&STp->lock);
@@ -3832,7 +3838,7 @@
 	tpnt->partition = 0;
 	tpnt->new_partition = 0;
 	tpnt->nbr_partitions = 0;
-	tpnt->timeout = ST_TIMEOUT;
+	tpnt->device->timeout = ST_TIMEOUT;
 	tpnt->long_timeout = ST_LONG_TIMEOUT;
 	tpnt->try_dio = try_direct_io && !SDp->host->unchecked_isa_dma;
 
--- diff/drivers/scsi/st.h	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/st.h	2004-05-27 18:34:18.000000000 +0100
@@ -100,7 +100,6 @@
 	unsigned char c_algo;			/* compression algorithm */
 	unsigned char pos_unknown;			/* after reset position unknown */
 	int tape_type;
-	int timeout;		/* timeout for normal commands */
 	int long_timeout;	/* timeout for commands known to take long time */
 
 	unsigned long max_pfn;	/* the maximum page number reachable by the HBA */
--- diff/drivers/scsi/tmscsim.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/tmscsim.c	2004-05-27 18:34:18.000000000 +0100
@@ -168,6 +168,10 @@
  *	2.1a  03/11/29  GL, KG	Initial fixing for 2.6. Convert to	*
  *				use the current PCI-mapping API, update	*
  *				command-queuing.			*
+ *	2.1b  04/04/13  GL	Fix for 64-bit platforms		*
+ *	2.1b1 04/01/31	GL	(applied 05.04) Remove internal		*
+ *				command-queuing.			*
+ *	2.1b2 04/02/01	CH	(applied 05.04) Fix error-handling	*
  ***********************************************************************/
 
 /* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
@@ -260,16 +264,10 @@
  * undef  : traditional save_flags; cli; restore_flags;
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
-# include <linux/init.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
-# include <linux/spinlock.h>
-#else
-# include <asm/spinlock.h>
-#endif
-#endif
+#include <linux/init.h>
+#include <linux/spinlock.h>
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,99) && defined(MODULE)
+#if defined(MODULE)
 static struct pci_device_id tmscsim_pci_tbl[] = {
 	{
 		.vendor		= PCI_VENDOR_ID_AMD,
@@ -283,23 +281,10 @@
 #endif
 	
 #define USE_SPINLOCKS 1
-#define NEW_PCI 1
 
-#define DC390_AFLAGS 
 #define DC390_IFLAGS unsigned long iflags
-#define DC390_DFLAGS unsigned long dflags
-spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
 #define DC390_LOCK_IO(dev) spin_lock_irqsave (((struct Scsi_Host *)dev)->host_lock, iflags)
 #define DC390_UNLOCK_IO(dev) spin_unlock_irqrestore (((struct Scsi_Host *)dev)->host_lock, iflags)
-#define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
-#define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
-#define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
-#define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
-#define DC390_LOCK_ACB /* DC390_LOCK_IO */
-#define DC390_UNLOCK_ACB /* DC390_UNLOCK_IO */
-#define DC390_LOCK_ACB_NI /* spin_lock (&(pACB->lock)) */
-#define DC390_UNLOCK_ACB_NI /* spin_unlock (&(pACB->lock)) */
-#define DC390_LOCKA_INIT /* DC390_LOCKA_INIT */
 
 /* These macros are used for uniform access to 2.0.x and 2.1.x PCI config space*/
 
@@ -313,10 +298,7 @@
 #define PCI_READ_CONFIG_BYTE(pd, rv, bv) pci_read_config_byte (pd, rv, bv)
 #define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pci_write_config_word (pd, rv, bv)
 #define PCI_READ_CONFIG_WORD(pd, rv, bv) pci_read_config_word (pd, rv, bv)
-#define PCI_BUS_DEV pdev->bus->number, pdev->devfn
 #define PCI_PRESENT (1)
-#define PCI_SET_MASTER pci_set_master (pdev)
-#define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev))
 #define PCI_GET_IO_AND_IRQ do{io_port = pci_resource_start (pdev, 0); irq = pdev->irq;} while(0)
 
 #include "tmscsim.h"
@@ -325,46 +307,42 @@
 # define __init
 #endif
 
-UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
-void dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-void dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-void dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-void dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-void dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 static void dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
 
 static void dc390_SetXferRate( PACB pACB, PDCB pDCB );
-void dc390_Disconnect( PACB pACB );
-void dc390_Reselect( PACB pACB );
-void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
-void dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd );
+static void dc390_Disconnect( PACB pACB );
+static void dc390_Reselect( PACB pACB );
+static void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd );
 static void dc390_ScsiRstDetect( PACB pACB );
 static void dc390_ResetSCSIBus( PACB pACB );
 static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
 static void __inline__ dc390_InvalidCmd( PACB pACB );
 static void __inline__ dc390_EnableMsgOut_Abort (PACB, PSRB);
 static void dc390_remove_dev (PACB pACB, PDCB pDCB);
-irqreturn_t do_DC390_Interrupt( int, void *, struct pt_regs *);
+static irqreturn_t do_DC390_Interrupt( int, void *, struct pt_regs *);
 
-int    dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index );
-void   dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun);
-void   dc390_updateDCB (PACB pACB, PDCB pDCB);
+static int    dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index );
+static void   dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun);
+static void   dc390_updateDCB (PACB pACB, PDCB pDCB);
 
 static int DC390_release(struct Scsi_Host *host);
 static int dc390_shutdown (struct Scsi_Host *host);
 
-
-//static PSHT	dc390_pSHT_start = NULL;
-//static PSH	dc390_pSH_start = NULL;
-//static PSH	dc390_pSH_current = NULL;
 static PACB	dc390_pACB_start= NULL;
 static PACB	dc390_pACB_current = NULL;
 static ULONG	dc390_lastabortedpid = 0;
@@ -372,14 +350,11 @@
 static UCHAR	dc390_adapterCnt = 0;
 
 /* Startup values, to be overriden on the commandline */
-int tmscsim[] = {-2, -2, -2, -2, -2, -2};
+static int tmscsim[] = {-2, -2, -2, -2, -2, -2};
 
-# if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
+#if defined(MODULE)
 MODULE_PARM(tmscsim, "1-6i");
 MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)");
-# endif
-
-#if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
 MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
 MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
 MODULE_LICENSE("GPL");
@@ -438,22 +413,15 @@
 #endif   
 
 /* Devices erroneously pretending to be able to do TagQ */
-UCHAR  dc390_baddevname1[2][28] ={
+static UCHAR  dc390_baddevname1[2][28] ={
        "SEAGATE ST3390N         9546",
        "HP      C3323-300       4269"};
 #define BADDEVCNT	2
 
 static char*  dc390_adapname = "DC390";
-UCHAR  dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
-UCHAR  dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
-UCHAR  dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,30)
-struct proc_dir_entry	DC390_proc_scsi_tmscsim ={
-       PROC_SCSI_DC390T, 7 ,"tmscsim",
-       S_IFDIR | S_IRUGO | S_IXUGO, 2
-       };
-#endif
+static UCHAR  dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
+static UCHAR  dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+static UCHAR  dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20};
 
 /***********************************************************************
  * Functions for access to DC390 EEPROM
@@ -518,7 +486,7 @@
 }
 
 
-int __initdata tmscsim_def[] = {7, 0 /* 10MHz */,
+static int __initdata tmscsim_def[] = {7, 0 /* 10MHz */,
 		PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_
 		| SYNC_NEGO_ | TAG_QUEUEING_,
 		MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION
@@ -549,8 +517,7 @@
 /* Override defaults on cmdline:
  * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
  */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
-int __init dc390_setup (char *str)
+static int __init dc390_setup (char *str)
 {	
 	int ints[8];
 	int i, im;
@@ -570,24 +537,6 @@
 __setup("tmscsim=", dc390_setup);
 #endif
 
-#else
-void __init dc390_setup (char *str, int *ints)
-{
-	int i, im;
-	im = ints[0];
-	if (im > 6)
-	{
-		printk (KERN_NOTICE "DC390: ignore extra params!\n");
-		im = 6;
-	}
-	for (i = 0; i < im; i++)
-		tmscsim[i] = ints[i+1];
-	/* dc390_checkparams (); */
-}
-#endif
-
-
-
 static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry )
 {
     UCHAR bval;
@@ -751,37 +700,6 @@
     return q;
 }
 #endif
-    
-
-/* Append to Query List */
-static void dc390_Query_append( PSCSICMD cmd, PACB pACB )
-{
-	dc390_cmd_scp_t *cmdq = (dc390_cmd_scp_t *)&cmd->SCp;
-
-	DEBUG0(printk ("DC390: Append cmd %li to Query\n", cmd->pid));
-
-	list_add_tail(&cmdq->list, &pACB->cmdq);
-	pACB->QueryCnt++;
-	pACB->CmdOutOfSRB++;
-}
-
-
-/* Return next cmd from Query list */
-static PSCSICMD dc390_Query_get ( PACB pACB )
-{
-	PSCSICMD  pcmd;
-	dc390_cmd_scp_t *cmdq;
-	if (list_empty(&pACB->cmdq))
-		return NULL;
-
-	pcmd = (PSCSICMD) list_entry(pACB->cmdq.next, struct scsi_cmnd_list, scp.list);
-	DEBUG0(printk ("DC390: Get cmd %li from Query\n", pcmd->pid));
-	cmdq = (dc390_cmd_scp_t *)&pcmd->SCp;
-	list_del(&cmdq->list);
-	pACB->QueryCnt--;
-	return pcmd;
-}
-
 
 /* Return next free SRB */
 static __inline__ PSRB dc390_Free_get ( PACB pACB )
@@ -891,17 +809,7 @@
 	dc390_Going_append (pDCB, pSRB);
 }
 
-/* 2.0 timer compatibility */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,30)
- static inline int timer_pending(struct timer_list * timer)
- {
-	return timer->prev != NULL;
- }
- #define time_after(a,b)         ((long)(b) - (long)(a) < 0)
- #define time_before(a,b)        time_after(b,a)
-#endif
-
-void DC390_waiting_timed_out (unsigned long ptr);
+static void DC390_waiting_timed_out (unsigned long ptr);
 /* Sets the timer to wake us up */
 static void dc390_waiting_timer (PACB pACB, unsigned long to)
 {
@@ -954,16 +862,13 @@
 }
 
 /* Wake up waiting queue */
-void DC390_waiting_timed_out (unsigned long ptr)
+static void DC390_waiting_timed_out (unsigned long ptr)
 {
 	PACB pACB = (PACB)ptr;
 	DC390_IFLAGS;
-	DC390_AFLAGS;
 	DEBUG0(printk ("DC390: Debug: Waiting queue woken up by timer!\n"));
 	DC390_LOCK_IO(pACB->pScsiHost);
-	DC390_LOCK_ACB;
 	dc390_Waiting_process (pACB);
-	DC390_UNLOCK_ACB;
 	DC390_UNLOCK_IO(pACB->pScsiHost);
 }
 
@@ -1022,7 +927,7 @@
 			pci_map_page(pdev, virt_to_page(pcmd->sense_buffer),
 				     (unsigned long)pcmd->sense_buffer & ~PAGE_MASK, sizeof(pcmd->sense_buffer),
 				     DMA_FROM_DEVICE);
-		pSRB->Segmentx.length = sizeof(pcmd->sense_buffer);
+		sg_dma_len(&pSRB->Segmentx) = sizeof(pcmd->sense_buffer);
 		pSRB->SGcount = 1;
 		pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
 		DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __FUNCTION__, pcmd->sense_buffer, cmdp->saved_dma_handle));
@@ -1043,7 +948,7 @@
 				     (unsigned long)pcmd->request_buffer & ~PAGE_MASK,
 				     pcmd->request_bufflen, scsi_to_pci_dma_dir(pcmd->sc_data_direction));
 		/* TODO: error handling */
-		pSRB->Segmentx.length = pcmd->request_bufflen;
+		sg_dma_len(&pSRB->Segmentx) = pcmd->request_bufflen;
 		pSRB->SGcount = 1;
 		pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
 		DEBUG1(printk("%s(): Mapped request buffer %p at %x\n", __FUNCTION__, pcmd->request_buffer, cmdp->saved_dma_handle));
@@ -1113,37 +1018,6 @@
     /* KG: deferred PCI mapping to dc390_StartSCSI */
 }
 
-/* Put cmnd from Query to Waiting list and send next Waiting cmnd */
-static void dc390_Query_to_Waiting (PACB pACB)
-{
-    Scsi_Cmnd *pcmd;
-    PSRB   pSRB;
-    PDCB   pDCB;
-
-    if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
-	return;
-
-    while (pACB->QueryCnt)
-    {
-	pSRB = dc390_Free_get ( pACB );
-	if (!pSRB) return;
-	pcmd = dc390_Query_get ( pACB );
-	if (!pcmd) { dc390_Free_insert (pACB, pSRB); return; } /* should not happen */
-	pDCB = dc390_findDCB (pACB, pcmd->device->id, pcmd->device->lun);
-	if (!pDCB) 
-	{ 
-		dc390_Free_insert (pACB, pSRB);
-		printk (KERN_ERR "DC390: Command in queue to non-existing device!\n");
-		pcmd->result = MK_RES(DRIVER_ERROR,DID_ERROR,0,0);
-		DC390_UNLOCK_ACB_NI;
-		pcmd->done (pcmd);
-		DC390_LOCK_ACB_NI;
-	}
-	dc390_BuildSRB (pcmd, pDCB, pSRB);
-	dc390_Waiting_append ( pDCB, pSRB );
-    }
-}
-
 /***********************************************************************
  * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
  *					       void (*done)(Scsi_Cmnd *))
@@ -1163,24 +1037,17 @@
  *
  ***********************************************************************/
 
-int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+static int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
     PDCB   pDCB;
     PSRB   pSRB;
     PACB   pACB = (PACB) cmd->device->host->hostdata;
-    DC390_AFLAGS;
-
 
     DEBUG0(/*  if(pACB->scan_devices) */	\
 	printk(KERN_INFO "DC390: Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li), buffer=%p\n",\
 	       cmd->cmnd[0],cmd->device->id,cmd->device->lun,cmd->pid, cmd->buffer));
 
-    DC390_LOCK_ACB;
-    
-    /* Assume BAD_TARGET; will be cleared later */
-    cmd->result = DID_BAD_TARGET << 16;
-   
-    /* TODO: Change the policy: Alway accept TEST_UNIT_READY or INQUIRY 
+    /* TODO: Change the policy: Always accept TEST_UNIT_READY or INQUIRY 
      * commands and alloc a DCB for the device if not yet there. DCB will
      * be removed in dc390_SRBdone if SEL_TIMEOUT */
 
@@ -1190,17 +1057,6 @@
     else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) )
 	pACB->scan_devices = 0;
 
-    if ( ( cmd->device->id >= pACB->pScsiHost->max_id ) || 
-	 (cmd->device->lun >= pACB->pScsiHost->max_lun) )
-    {
-/*	printk ("DC390: Ignore target %d lun %d\n",
-		cmd->device->id, cmd->device->lun); */
-	DC390_UNLOCK_ACB;
-	//return (1);
-	done (cmd);
-	return (0);
-    }
-
     if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY || cmd->cmnd[0] == INQUIRY) && 
        !(pACB->DCBmap[cmd->device->id] & (1 << cmd->device->lun)) )
     {
@@ -1211,14 +1067,7 @@
 	  {
 	    printk (KERN_ERR "DC390: kmalloc for DCB failed, target %02x lun %02x\n", 
 		    cmd->device->id, cmd->device->lun);
-	    DC390_UNLOCK_ACB;
-	    printk ("DC390: No DCB in queue_command!\n");
-#ifdef USE_NEW_EH
-	    return (1);
-#else
-	    done (cmd);
-	    return (0);
-#endif
+	    goto fail;
 	  }
             
     }
@@ -1226,10 +1075,7 @@
     {
 	printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n",
 		cmd->device->id, cmd->device->lun); 
-	DC390_UNLOCK_ACB;
-	//return (1);
-	done (cmd);
-	return (0);
+	goto fail;
     }
     else
     {
@@ -1238,60 +1084,34 @@
 	 {  /* should never happen */
 	    printk (KERN_ERR "DC390: no DCB failed, target %02x lun %02x\n", 
 		    cmd->device->id, cmd->device->lun);
-	    DC390_UNLOCK_ACB;
-	    printk ("DC390: No DCB in queuecommand (2)!\n");
-#ifdef USE_NEW_EH
-	    return (1);
-#else
-	    done (cmd);
-	    return (0);
-#endif
+	    goto fail;
 	 }
     }
 
     pACB->Cmds++;
     cmd->scsi_done = done;
     cmd->result = 0;
-	
-    dc390_Query_to_Waiting (pACB);
 
-    if( pACB->QueryCnt ) /* Unsent commands ? */
-    {
-	DEBUG0(printk ("DC390: QueryCnt != 0\n"));
-	dc390_Query_append ( cmd, pACB );
-	dc390_Waiting_process (pACB);
-    }
-    else if (pDCB->pWaitingSRB)
-    {
- 	pSRB = dc390_Free_get ( pACB );
-	DEBUG0(if (!pSRB) printk ("DC390: No free SRB but Waiting\n"); else printk ("DC390: Free SRB w/ Waiting\n"));
-	if (!pSRB) dc390_Query_append (cmd, pACB);
-	else 
-	  {
-	    dc390_BuildSRB (cmd, pDCB, pSRB);
-	    dc390_Waiting_append (pDCB, pSRB);
-	  }
-	dc390_Waiting_process (pACB);
-    }
-    else
-    {
- 	pSRB = dc390_Free_get ( pACB );
-	DEBUG0(if (!pSRB) printk ("DC390: No free SRB w/o Waiting\n"); else printk ("DC390: Free SRB w/o Waiting\n"));
-	if (!pSRB)
-	{
-	    dc390_Query_append (cmd, pACB);
-	    dc390_Waiting_process (pACB);
-	}
-	else 
-	{
-	    dc390_BuildSRB (cmd, pDCB, pSRB);
-	    dc390_SendSRB (pACB, pSRB);
-	}
-    }
+    pSRB = dc390_Free_get(pACB);
+    if (!pSRB)
+	    goto requeue;
+
+    dc390_BuildSRB(cmd, pDCB, pSRB);
+    if (pDCB->pWaitingSRB) {
+	    dc390_Waiting_append(pDCB, pSRB);
+	    dc390_Waiting_process(pACB);
+    } else
+	    dc390_SendSRB(pACB, pSRB);
 
-    DC390_UNLOCK_ACB;
     DEBUG1(printk (KERN_DEBUG " ... command (pid %li) queued successfully.\n", cmd->pid));
     return(0);
+
+ requeue:
+    return 1;
+ fail:
+    cmd->result = DID_BAD_TARGET << 16;
+    done(cmd);
+    return 0;
 }
 
 /* We ignore mapping problems, as we expect everybody to respect 
@@ -1384,8 +1204,8 @@
  * Note:
  *   In contrary to other externally callable funcs (DC390_), we don't lock
  ***********************************************************************/
-int DC390_bios_param (struct scsi_device *sdev, struct block_device *bdev,
-		sector_t capacity, int geom[])
+static int DC390_bios_param (struct scsi_device *sdev, struct block_device *bdev,
+			     sector_t capacity, int geom[])
 {
     int heads, sectors, cylinders;
     PACB pACB = (PACB) sdev->host->hostdata;
@@ -1421,15 +1241,14 @@
     return (0);
 }
 #else
-int DC390_bios_param (struct scsi_device *sdev, struct block_device *bdev,
-		sector_t capacity, int geom[])
+static int DC390_bios_param (struct scsi_device *sdev, struct block_device *bdev,
+			     sector_t capacity, int geom[])
 {
     return scsicam_bios_param (bdev, capacity, geom);
 }
 #endif
 
-
-void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB)
+static void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB)
 {
     USHORT pstat; PDEVDECL1;
     if (!pDCB) pDCB = pACB->pActiveDCB;
@@ -1483,7 +1302,7 @@
  * Status: Buggy !
  ***********************************************************************/
 
-int DC390_abort (Scsi_Cmnd *cmd)
+static int DC390_abort (Scsi_Cmnd *cmd)
 {
     PDCB  pDCB;
     PSRB  pSRB, psrb;
@@ -1491,28 +1310,10 @@
     int   status;
     //ULONG sbac;
     PACB  pACB = (PACB) cmd->device->host->hostdata;
-    DC390_AFLAGS;
-
-    DC390_LOCK_ACB;
 
     printk ("DC390: Abort command (pid %li, Device %02i-%02i)\n",
 	    cmd->pid, cmd->device->id, cmd->device->lun);
 
-    /* First scan Query list */
-    if( pACB->QueryCnt )
-    {
-	struct scsi_cmnd_list *t, *pcmd_l;
-	list_for_each_entry_safe(pcmd_l, t, &pACB->cmdq, scp.list)
-		if( (struct scsi_cmnd*)pcmd_l == cmd )
-		{
-			/* Found: Dequeue */
-			list_del(&pcmd_l->scp.list);
-			pACB->QueryCnt--;
-			status = SCSI_ABORT_SUCCESS;
-			goto  ABO_X;
-		}
-    }
-	
     pDCB = dc390_findDCB (pACB, cmd->device->id, cmd->device->lun);
     if( !pDCB ) goto  NOT_RUN;
 
@@ -1625,7 +1426,6 @@
     }
 #endif
     dc390_lastabortedpid = cmd->pid;
-    DC390_UNLOCK_ACB;
     //do_DC390_Interrupt (pACB->IRQLevel, 0, 0);
 #ifndef USE_NEW_EH	
     if (status == SCSI_ABORT_SUCCESS) cmd->scsi_done(cmd);
@@ -1708,15 +1508,13 @@
  * Returns : 0 on success.
  ***********************************************************************/
 
-int DC390_reset (Scsi_Cmnd *cmd)
+static int DC390_reset (Scsi_Cmnd *cmd)
 {
     UCHAR   bval;
     PACB    pACB = (PACB) cmd->device->host->hostdata;
-    DC390_AFLAGS;
 
     printk(KERN_INFO "DC390: RESET ... ");
 
-    DC390_LOCK_ACB;
     if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer);
     bval = DC390_read8 (CtrlReg1);
     bval |= DIS_INT_ON_SCSI_RST;
@@ -1745,7 +1543,6 @@
     dc390_Waiting_process( pACB );
 
     printk("done\n");
-    DC390_UNLOCK_ACB;
     return( SCSI_RESET_SUCCESS );
 }
 
@@ -1760,14 +1557,14 @@
  * Inputs : SCSI id and lun
  ***********************************************************************/
 
-void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun )
+static void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun )
 {
     PEEprom	prom;
     UCHAR	index;
     PDCB pDCB, pDCB2;
 
     pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC);
-    DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): %p\n"	\
+    DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): %p\n",	\
 		     id, lun, pDCB));
  
     *ppDCB = pDCB;
@@ -1845,7 +1642,7 @@
  * Purpose :  Set the configuration dependent DCB parameters
  ***********************************************************************/
 
-void dc390_updateDCB (PACB pACB, PDCB pDCB)
+static void dc390_updateDCB (PACB pACB, PDCB pDCB)
 {
   pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE /*| EN_ATN_STOP*/;
   if (pDCB->DevMode & TAG_QUEUEING_) {
@@ -1869,25 +1666,6 @@
 	pDCB->CtrlR1 |= PARITY_ERR_REPO;
 }  
 
-
-/***********************************************************************
- * Function : static void dc390_updateDCBs ()
- *
- * Purpose :  Set the configuration dependent DCB params for all DCBs
- ***********************************************************************/
-
-static void dc390_updateDCBs (PACB pACB)
-{
-  int i;
-  PDCB pDCB = pACB->pLinkDCB;
-  for (i = 0; i < pACB->DCBCnt; i++)
-    {
-      dc390_updateDCB (pACB, pDCB);
-      pDCB = pDCB->pNextDCB;
-    }
-}
-  
-
 /***********************************************************************
  * Function : static void dc390_initSRB()
  *
@@ -1902,7 +1680,7 @@
 }
 
 
-void dc390_linkSRB( PACB pACB )
+static void dc390_linkSRB( PACB pACB )
 {
     UINT   count, i;
 
@@ -1927,11 +1705,10 @@
  *	    io_port, Irq, index: Resources and adapter index
  ***********************************************************************/
 
-void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
+static void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
     PACB    pACB;
     UCHAR   i;
-    DC390_AFLAGS;
 
     psh->can_queue = MAX_CMD_QUEUE;
     psh->cmd_per_lun = MAX_CMD_PER_LUN;
@@ -1939,11 +1716,7 @@
     psh->io_port = io_port;
     psh->n_io_port = 0x80;
     psh->irq = Irq;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,50)
     psh->base = io_port;
-#else
-    psh->base = (char*)io_port;
-#endif	
     psh->unique_id = io_port;
     psh->dma_channel = -1;
     psh->last_reset = jiffies;
@@ -1970,8 +1743,6 @@
     pACB->pActiveDCB = NULL;
     pACB->pFreeSRB = pACB->SRB_array;
     pACB->SRBCount = MAX_SRB_CNT;
-    pACB->QueryCnt = 0;
-    INIT_LIST_HEAD(&pACB->cmdq);
     pACB->AdapterIndex = index;
     pACB->status = 0;
     psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
@@ -2007,7 +1778,7 @@
  * Outputs: 0 on success, -1 on error
  ***********************************************************************/
 
-int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
+static int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
     PACB   pACB, pACB2;
     UCHAR  dstate;
@@ -2086,7 +1857,7 @@
  * Inputs : host - pointer to this host adapter's structure
  *	    io_port - IO ports mapped to this adapter
  *	    Irq - IRQ assigned to this adpater
- *	    PDEVDECL - PCI access handle
+ *	    struct pci_dev - PCI access handle
  *	    index - Adapter index
  *
  * Outputs: 0 on success, -1 on error
@@ -2095,12 +1866,11 @@
  *	not in DC390_detect, called from outside 
  ***********************************************************************/
 
-static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, UCHAR index)
+static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, UCHAR index)
 {
     PSH   psh;
     PACB  pACB;
-    DC390_AFLAGS;
-    
+
     if (dc390_CheckEEpromCheckSum (PDEV, index))
     {
 	int speed;
@@ -2126,21 +1896,6 @@
 	
     scsi_set_device(psh, &pdev->dev);
     pACB = (PACB) psh->hostdata;
-    DC390_LOCKA_INIT;
-    DC390_LOCK_ACB;
-
-#if 0
-    if( !dc390_pSH_start )
-    {
-        dc390_pSH_start = psh;
-        dc390_pSH_current = psh;
-    }
-    else
-    {
-        dc390_pSH_current->next = psh;
-        dc390_pSH_current = psh;
-    }
-#endif
 
     DEBUG0(printk(KERN_INFO "DC390: pSH = %8x, Index %02i\n", (UINT) psh, index));
 
@@ -2154,59 +1909,15 @@
 		      (UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array));
 	DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\
 		      sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) ));
-
-	DC390_UNLOCK_ACB;
         return (0);
     }
     else
     {
-	//dc390_pSH_start = NULL;
 	scsi_unregister( psh );
-	DC390_UNLOCK_ACB;
 	return( -1 );
     }
 }
 
-
-/***********************************************************************
- * Function : int DC390_detect(Scsi_Host_Template *psht)
- *
- * Purpose : detects and initializes AMD53C974 SCSI chips
- *	     that were autoprobed, overridden on the LILO command line,
- *	     or specified at compile time.
- *
- * Inputs : psht - template for this SCSI adapter
- *
- * Returns : number of host adapters detected
- *
- ***********************************************************************/
-
-#ifndef NEW_PCI
-/* Acc. to PCI 2.1 spec it's up to the driver to enable Bus mastering:
- * We use pci_set_master () for 2.1.x and this func for 2.0.x:	*/
-static void __init dc390_set_master (PDEVDECL)
-{
-	USHORT cmd;
-	UCHAR lat;
-	
-	PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
-	
-        if (! (cmd & PCI_COMMAND_MASTER)) {	
-		printk("PCI: Enabling bus mastering for device %02x:%02x\n",
-		       PCI_BUS_DEV);
-		cmd |= PCI_COMMAND_MASTER;
-		PCI_WRITE_CONFIG_WORD(PDEV, PCI_COMMAND, cmd);
-	}
-	PCI_READ_CONFIG_BYTE (PDEV, PCI_LATENCY_TIMER, &lat);
-	if (lat < 16 /* || lat == 255 */) {
-		printk("PCI: Setting latency timer of device %02x:%02x from %i to 64\n",
-		       PCI_BUS_DEV, lat);
-		PCI_WRITE_CONFIG_BYTE(PDEV, PCI_LATENCY_TIMER, 64);
-	}
-	
-}
-#endif /* ! NEW_PCI */
-
 static void __init dc390_set_pci_cfg (PDEVDECL)
 {
 	USHORT cmd;
@@ -2215,30 +1926,31 @@
 	PCI_WRITE_CONFIG_WORD (PDEV, PCI_COMMAND, cmd);
 	PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));
 }
-	
 
 int __init DC390_detect (Scsi_Host_Template *psht)
 {
-    PDEVDECL0;
+    struct pci_dev *pdev = NULL;
     UCHAR   irq;
     ULONG   io_port;
 
-    //dc390_pSHT_start = psht;
     dc390_pACB_start = NULL;
 
     if ( PCI_PRESENT )
-	while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974))
+	    while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, pdev)))
 	{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30)
 	    if (pci_enable_device (pdev))
 		continue;
-#endif
+
+	    if (pci_set_dma_mask(pdev, 0xffffffff)) {
+		    printk(KERN_ERR "DC390(%i): No suitable DMA available.\n", dc390_adapterCnt);
+		    continue;
+	    }
 	    PCI_GET_IO_AND_IRQ;
 	    DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq));
 
 	    if( !DC390_init(psht, io_port, irq, PDEV, dc390_adapterCnt))
 	    {
-		PCI_SET_MASTER;
+		pci_set_master(pdev);
 		dc390_set_pci_cfg (PDEV);
 		dc390_adapterCnt++;
 	    }
@@ -2247,495 +1959,12 @@
 	printk (KERN_ERR "DC390: No PCI BIOS found!\n");
    
     if (dc390_adapterCnt)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
 	psht->proc_name = "tmscsim";
-#else
-	psht->proc_dir = &DC390_proc_scsi_tmscsim;
-#endif
+
     printk(KERN_INFO "DC390: %i adapters found\n", dc390_adapterCnt);
     return( dc390_adapterCnt );
 }
 
-
-/***********************************************************************
- * Functions: dc390_inquiry(), dc390_inquiry_done()
- *
- * Purpose: When changing speed etc., we have to issue an INQUIRY
- *	    command to make sure, we agree upon the nego parameters
- *	    with the device
- ***********************************************************************/
-
-static void dc390_inquiry_done (Scsi_Cmnd* cmd)
-{
-   printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n",
-	   cmd->device->id, cmd->device->lun, cmd->result);
-   if (cmd->result)
-   {
-	PACB pACB = (PACB)cmd->device->host->hostdata;
-	PDCB pDCB = dc390_findDCB (pACB, cmd->device->id, cmd->device->lun);
-	printk ("DC390: Unsetting DsCn, Sync and TagQ!\n");
-	if (pDCB)
-	{
-		pDCB->DevMode &= ~(SYNC_NEGO_ | TAG_QUEUEING_ | EN_DISCONNECT_ );
-		dc390_updateDCB (pACB, pDCB);
-	}
-   }
-   kfree (cmd);
-}
-
-void dc390_inquiry (PACB pACB, PDCB pDCB)
-{
-   char* buffer;
-   Scsi_Cmnd* cmd;
-   cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC);
-   if (!cmd) { printk ("DC390: kmalloc failed in inquiry!\n"); return; }
-   buffer = (char*)cmd + sizeof(Scsi_Cmnd);
-
-   memset (cmd, 0, sizeof(Scsi_Cmnd) + 256);
-   cmd->cmnd[0] = INQUIRY;
-   cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0;
-   cmd->cmnd[4] = 0xff;
-   
-   cmd->cmd_len = 6; cmd->old_cmd_len = 6;
-/* TODO FIXME */
-/*    cmd->host = pACB->pScsiHost; */
-   cmd->device->id = pDCB->TargetID;
-   cmd->device->lun = pDCB->TargetLUN; 
-   cmd->serial_number = 1;
-   cmd->pid = 390;
-   cmd->bufflen = 128;
-   cmd->buffer = buffer;
-   cmd->request_bufflen = 128;
-   cmd->request_buffer = &buffer[128];
-   cmd->done = dc390_inquiry_done;
-   cmd->scsi_done = dc390_inquiry_done;
-   cmd->timeout_per_command = HZ;
-
-   cmd->request->rq_status = RQ_SCSI_BUSY;
-
-   pDCB->SyncMode &= ~SYNC_NEGO_DONE;
-   printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n",
-	   pDCB->TargetID, pDCB->TargetLUN);
-   DC390_queue_command (cmd, dc390_inquiry_done);
-}
-
-/***********************************************************************
- * Functions: dc390_sendstart(), dc390_sendstart_done()
- *
- * Purpose: When changing speed etc., we have to issue an INQUIRY
- *	    command to make sure, we agree upon the nego parameters
- *	    with the device
- ***********************************************************************/
-
-static void dc390_sendstart_done (Scsi_Cmnd* cmd)
-{
-   printk (KERN_INFO "DC390: SENDSTART (ID %02x LUN %02x) returned %08x\n",
-	   cmd->device->id, cmd->device->lun, cmd->result);
-   kfree (cmd);
-}
-
-void dc390_sendstart (PACB pACB, PDCB pDCB)
-{
-   char* buffer;
-   Scsi_Cmnd* cmd;
-   cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC);
-   if (!cmd) { printk ("DC390: kmalloc failed in sendstart!\n"); return; }
-   buffer = (char*)cmd + sizeof(Scsi_Cmnd);
-
-   memset (cmd, 0, sizeof(Scsi_Cmnd) + 256);
-   cmd->cmnd[0] = 0x1b; /* START_STOP_UNIT */
-   cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0;
-   cmd->cmnd[4] = 0x01; /* START */
-   
-   cmd->cmd_len = 6; cmd->old_cmd_len = 6;
-/* TODO FIXME */
-/*    cmd->host = pACB->pScsiHost; */
-   cmd->device->id = pDCB->TargetID;
-   cmd->device->lun = pDCB->TargetLUN; 
-   cmd->serial_number = 1;
-   cmd->pid = 310;
-   cmd->bufflen = 128;
-   cmd->buffer = buffer;
-   cmd->request_bufflen = 128;
-   cmd->request_buffer = &buffer[128];
-   cmd->done = dc390_sendstart_done;
-   cmd->scsi_done = dc390_sendstart_done;
-   cmd->timeout_per_command = 5*HZ;
-
-   cmd->request->rq_status = RQ_SCSI_BUSY;
-
-   pDCB->SyncMode &= ~SYNC_NEGO_DONE;
-   printk (KERN_INFO "DC390: Queue SEND_START command to dev ID %02x LUN %02x\n",
-	   pDCB->TargetID, pDCB->TargetLUN);
-   DC390_queue_command (cmd, dc390_sendstart_done);
-}
-
-/********************************************************************
- * Function: dc390_set_info()
- *
- * Purpose: Change adapter config
- *
- * Strings are parsed similar to the output of tmscsim_proc_info ()
- * '-' means no change
- *******************************************************************/
-
-static int dc390_scanf (char** buffer, char** pos, char** p0, int* var)
-{
-   *p0 = *pos;
-   *var = simple_strtoul (*p0, pos, 10);
-   if (*p0 == *pos) return -1;
-   *pos = strsep (buffer, " \t\n:=,;.");
-   return 0;
-}
-
-#define SCANF(buffer, pos, p0, var, min, max)		\
-if (dc390_scanf (&buffer, &pos, &p0, &var)) goto einv;	\
-else if (var<min || var>max) goto einv2
-
-static int dc390_yesno (char** buffer, char** pos, char* var, char bmask)
-{
-   switch (**pos)
-     {
-      case 'Y': *var |= bmask; break;
-      case 'N': *var &= ~bmask; break;
-      case '-': break;
-      default: return -1;
-     }
-   *pos = strsep (buffer, " \t\n:=,;");
-   return 0;
-}
-
-#define YESNO(buffer, pos, var, bmask)					\
-	if (dc390_yesno (&buffer, &pos, &var, bmask)) goto einv;	\
-	else dc390_updateDCB (pACB, pDCB);				\
-	if (!pos) goto ok
-
-static int dc390_search (char** buffer, char** pos, char** p0, char* var, char* txt, int max, int scale, char* ign)
-{
-   int dum;
-   if (! memcmp (*pos, txt, strlen(txt)))
-     {
-	*p0 = strsep (buffer, " \t\n:=,;");
-	if (!*p0) return -1;
-	dum = simple_strtoul (*p0, pos, 10);
-	if (*p0 == *pos) return -1;
-	if (dum >= 0 && dum <= max) 
-	  { *var = (dum * 100) / scale; }
-	else return -2;
-	*pos = strsep (buffer, " \t\n:=,;");
-	if (*ign && *pos && strlen(*pos) >= strlen(ign) && 
-	    !(memcmp (*pos, ign, strlen(ign)))) 
-		*pos = strsep (buffer, " \t\n:=,;");
-
-     }
-   return 0;
-}
-
-#define SEARCH(buffer, pos, p0, var, txt, max)						\
-if (dc390_search (&buffer, &pos, &p0, (PUCHAR)(&var), txt, max, 100, "")) goto einv2;	\
-else if (!p1) goto ok2
-
-#define SEARCH2(buffer, pos, p0, var, txt, max, scale)					\
-if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; 		\
-else if (!p1) goto ok2
-
-#define SEARCH3(buffer, pos, p0, var, txt, max, scale, ign)				\
-if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, ign)) goto einv2;		\
-else if (!p1) goto ok2
-
-
-#ifdef DC390_PARSEDEBUG
-static char _prstr[256];
-char* prstr (char* p, char* e)
-{
-   char* c = _prstr;
-   while (p < e)
-     if (*p == 0) { *c++ = ':'; p++; }
-     else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; }
-     else *c++ = *p++;
-   *c = 0;
-   return _prstr;
-}
-#endif
-
-int dc390_set_info (char *buffer, int length, PACB pACB)
-{
-  char *pos = buffer, *p0 = buffer;
-  char needs_inquiry = 0; 
-  int dum = 0;
-  char dev;
-  PDCB pDCB = pACB->pLinkDCB;
-  DC390_IFLAGS;
-  DC390_AFLAGS;
-  pos[length] = 0;
-
-  DC390_LOCK_IO(pACB->pScsiHost);
-  DC390_LOCK_ACB;
-  /* UPPERCASE */ 
-  /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */
-  while (*pos) 
-    { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; }
-  
-  /* Remove WS */
-  pos = strsep (&buffer, " \t:\n=,;");
-  if (!*pos) goto ok;
-   
- next:
-  if (!memcmp (pos, "RESET", 5)) goto reset;
-  else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry;
-  else if (!memcmp (pos, "REMOVE", 6)) goto remove;
-  else if (!memcmp (pos, "ADD", 3)) goto add;
-  else if (!memcmp (pos, "START", 5)) goto start;
-  else if (!memcmp (pos, "DUMP", 4)) goto dump;
-  
-  if (isdigit (*pos))
-    {
-      /* Device config line */
-      int dev, id, lun; char* pdec;
-      char olddevmode;
-      
-      SCANF (buffer, pos, p0, dev, 0, pACB->DCBCnt-1);
-      if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
-      if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
-      if (!*pos) goto einv;
-      
-      PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length])));
-      pDCB = pACB->pLinkDCB;
-      for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
-      /* Sanity Check */
-      if (pDCB->TargetID != id || pDCB->TargetLUN != lun) 
-	 {
-	    printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n",
-		    dev, id, lun);
-	    goto einv2;
-	 }
-
-      if (pDCB->pWaitingSRB || pDCB->pGoingSRB)
-      {
-	  printk ("DC390: Cannot change dev (%i-%i) cfg: Pending requests\n",
-		  pDCB->TargetID, pDCB->TargetLUN);
-	  goto einv;
-      }
-	  
-      olddevmode = pDCB->DevMode;
-      YESNO (buffer, pos, pDCB->DevMode, PARITY_CHK_);
-      needs_inquiry++;
-      YESNO (buffer, pos, pDCB->DevMode, SYNC_NEGO_);
-      if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
-      needs_inquiry++;
-      YESNO (buffer, pos, pDCB->DevMode, EN_DISCONNECT_);
-      if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
-      YESNO (buffer, pos, pDCB->DevMode, SEND_START_);
-      needs_inquiry++;
-      YESNO (buffer, pos, pDCB->DevMode, TAG_QUEUEING_);
-      if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
-
-      dc390_updateDCB (pACB, pDCB);
-      if (!*pos) goto ok;
-       
-      olddevmode = pDCB->NegoPeriod;
-      /* Look for decimal point (Speed) */
-      pdec = pos; 
-      while (pdec++ < &buffer[length]) if (*pdec == '.') break;
-      /* NegoPeriod */
-      if (*pos != '-')
-	{
-	  SCANF (buffer, pos, p0, dum, 72, 800); 
-	  pDCB->NegoPeriod = dum >> 2;
-	  if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
-	  if (!pos) goto ok;
-	  if (memcmp (pos, "NS", 2) == 0) pos = strsep (&pos, " \t\n:=,;.");
-	}
-      else pos = strsep (&pos, " \t\n:=,;.");
-      if (!*pos) goto ok;
-      
-      /* Sync Speed in MHz */
-      if (*pos != '-')
-	{
-	  SCANF (buffer, pos, p0, dum, 1, 13); 
-	  pDCB->NegoPeriod = (1000/dum) >> 2;
-	  if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
-	  if (!*pos) goto ok;
-	  /* decimal */
-	  if (pos-1 == pdec)
-	     {
-		int dumold = dum;
-		dum = simple_strtoul (pos, &p0, 10) * 10;
-		for (; p0-pos > 1; p0--) dum /= 10;
-		pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
-		if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
-		pos = strsep (&pos, " \t\n:=,;");
-		if (!*pos) goto ok;
-	     }
-	  if (*pos == 'M') pos = strsep (&pos, " \t\n:=,;");
-	  if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
-	}
-      else pos = strsep (&pos, " \t\n:=,;");
-      /* dc390_updateDCB (pACB, pDCB); */
-      if (!*pos) goto ok;
-
-      olddevmode = pDCB->SyncOffset;
-      /* SyncOffs */
-      if (*pos != '-')
-	{
-	  SCANF (buffer, pos, p0, dum, 0, 0x0f); 
-	  pDCB->SyncOffset = dum;
-	  if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
-	}
-      else pos = strsep (&pos, " \t\n:=,;");
-      if (!*pos) goto ok;
-      dc390_updateDCB (pACB, pDCB);
-
-      //olddevmode = pDCB->MaxCommand;
-      /* MaxCommand (Tags) */
-      if (*pos != '-')
-	{
-	  SCANF (buffer, pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
-	  if (pDCB->SyncMode & EN_TAG_QUEUEING)
-		pDCB->MaxCommand = dum;
-	  else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n");
-	}
-      else pos = strsep (&pos, " \t\n:=,;");
-
-    }
-  else
-    {
-      char* p1 = pos; UCHAR dum, newadaptid;
-      PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length])));
-      dum = GLITCH_TO_NS (pACB->glitch_cfg);
-      /* Adapter setting */
-      SEARCH (buffer, pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); 
-      SEARCH (buffer, pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); 
-      SEARCH (buffer, pos, p0, newadaptid, "ADAPTERID", 7);
-      SEARCH (buffer, pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
-      SEARCH (buffer, pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
-      SEARCH3 (buffer, pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
-      SEARCH3 (buffer, pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
-      SEARCH3 (buffer, pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
-    ok2:
-      pACB->glitch_cfg = NS_TO_GLITCH (dum);
-      if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
-      DC390_write8 (Scsi_TimeOut, pACB->sel_timeout);
-      if (newadaptid != pACB->pScsiHost->this_id)
-      {
-	pACB->pScsiHost->this_id = newadaptid;
-	dc390_ResetDevParam (pACB);
-      }	    
-      //dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
-      //pACB->TagMaxNum &= (1 << --dum);
-      dc390_updateDCBs (pACB);
-      // All devs should be INQUIRED now
-      if (pos == p1) goto einv;
-    }
-  if (*pos) goto next;
-      
- ok:
-  DC390_UNLOCK_ACB;
-  if (needs_inquiry) 
-     { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); }
-  DC390_UNLOCK_IO(pACB->pScsiHost);
-  return (length);
-
- einv2:
-  pos = p0;
- einv:
-  DC390_UNLOCK_ACB;
-  DC390_UNLOCK_IO(pACB->pScsiHost);
-  printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
-  return (-EINVAL);
-   
- reset:
-     {
-	Scsi_Cmnd cmd;
-	/* TODO FIXME */
-	/* cmd.host = pACB->pScsiHost; */
-	printk (KERN_WARNING "DC390: Driver reset requested!\n");
-	DC390_UNLOCK_ACB;
-	DC390_reset (&cmd);
-	DC390_UNLOCK_IO(pACB->pScsiHost);
-     }
-  return (length);
-
- dump:
-     {
-	dc390_dumpinfo (pACB, 0, 0);
-	DC390_UNLOCK_ACB;
-	DC390_UNLOCK_IO(pACB->pScsiHost);       
-     }
-  return (length);
-	
- inquiry:
-     {
-	pos = strsep (&pos, " \t\n.:;="); if (!*pos) goto einv;
-	dev = simple_strtoul (pos, &p0, 10);
-	if (dev >= pACB->DCBCnt) goto einv_dev;
-	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
-	printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n",
-		dev, pDCB->TargetID, pDCB->TargetLUN);
-	DC390_UNLOCK_ACB;
-	dc390_inquiry (pACB, pDCB);
-	DC390_UNLOCK_IO(pACB->pScsiHost);
-     }
-   return (length);
-
- remove:
-     {
-	pos = strsep (&pos, " \t\n.:;="); if (!*pos) goto einv;
-	dev = simple_strtoul (pos, &p0, 10);
-	if (dev >= pACB->DCBCnt) goto einv_dev;
-	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
-	printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n",
-		dev, pDCB->TargetID, pDCB->TargetLUN);
-	/* TO DO: We should make sure no pending commands are left */
-	dc390_remove_dev (pACB, pDCB);
-	DC390_UNLOCK_ACB;
-	DC390_UNLOCK_IO(pACB->pScsiHost);
-     }
-   return (length);
-
- add:
-     {
-	int id, lun;
-	pos = strsep (&pos, " \t\n.:;=");
-	if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
-	if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
-	pDCB = dc390_findDCB (pACB, id, lun);
-	if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; }
-	dc390_initDCB (pACB, &pDCB, id, lun);
-	DC390_UNLOCK_ACB;
-	dc390_inquiry (pACB, pDCB);
-	DC390_UNLOCK_IO(pACB->pScsiHost);
-     }
-   return (length);
-
- start:
-     {
-	int id, lun;
-	pos = strsep (&pos, " \t\n.:;=");
-	if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
-	if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
-	pDCB = dc390_findDCB (pACB, id, lun);
-	if (pDCB) printk ("DC390: SendStart: Device already existing ...\n");
-	else dc390_initDCB (pACB, &pDCB, id, lun);
-	DC390_UNLOCK_ACB;
-	dc390_sendstart (pACB, pDCB);
-	dc390_inquiry (pACB, pDCB);
-	DC390_UNLOCK_IO(pACB->pScsiHost);
-     }
-   return (length);
-
- einv_dev:
-   printk (KERN_WARNING "DC390: Ignore cmnd to invalid Dev(Idx) %i. Valid range: 0 - %i.\n", 
-	   dev, pACB->DCBCnt - 1);
-   DC390_UNLOCK_ACB;
-   DC390_UNLOCK_IO(pACB->pScsiHost);
-   return (-EINVAL);
-}
-
-#undef SEARCH
-#undef YESNO
-#undef SCANF
-
 /********************************************************************
  * Function: DC390_proc_info(char* buffer, char **start,
  *			     off_t offset, int length, int hostno, int inout)
@@ -2763,15 +1992,13 @@
  else SPRINTF(" No  ")
 
 
-int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start,
-		     off_t offset, int length, int inout)
+static int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start,
+			    off_t offset, int length, int inout)
 {
   int dev, spd, spd1;
   char *pos = buffer;
-  struct scsi_cmnd_list *cl;
   PACB pACB;
   PDCB pDCB;
-  DC390_AFLAGS;
 
   pACB = dc390_pACB_start;
 
@@ -2785,13 +2012,11 @@
   if (pACB == (PACB)-1) return(-ESRCH);
 
   if(inout) /* Has data been written to the file ? */
-      return dc390_set_info(buffer, length, pACB);
+      return -ENOSYS;
    
   SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, ");
   SPRINTF("Driver Version %s\n", DC390_VERSION);
 
-  DC390_LOCK_ACB;
-
   SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
   SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex);
   SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase);
@@ -2839,9 +2064,6 @@
       SPRINTF ("      %02i\n", pDCB->MaxCommand);
       pDCB = pDCB->pNextDCB;
      }
-    SPRINTF ("Commands in Queues: Query: %li:", pACB->QueryCnt);
-    list_for_each_entry(cl, &pACB->cmdq, scp.list)
-	SPRINTF (" %li", ((struct scsi_cmnd*)cl)->pid);
     if (timer_pending(&pACB->Waiting_Timer)) SPRINTF ("Waiting queue timer running\n");
     else SPRINTF ("\n");
     pDCB = pACB->pLinkDCB;
@@ -2876,8 +2098,6 @@
     SPRINTF("\n");
 #endif
   
-
-  DC390_UNLOCK_ACB;
   *start = buffer + offset;
 
   if (pos - buffer < offset)
@@ -2919,7 +2139,7 @@
     return( 0 );
 }
 
-void dc390_freeDCBs (struct Scsi_Host *host)
+static void dc390_freeDCBs (struct Scsi_Host *host)
 {
     PDCB pDCB, nDCB;
     PACB pACB = (PACB)(host->hostdata);
@@ -2938,13 +2158,12 @@
 
 }
 
-int DC390_release (struct Scsi_Host *host)
+static int DC390_release (struct Scsi_Host *host)
 {
-    DC390_AFLAGS DC390_IFLAGS;
+    DC390_IFLAGS;
     PACB pACB = (PACB)(host->hostdata);
 
     DC390_LOCK_IO(host);
-    DC390_LOCK_ACB;
 
     /* TO DO: We should check for outstanding commands first. */
     dc390_shutdown (host);
@@ -2957,7 +2176,6 @@
 
     release_region(host->io_port,host->n_io_port);
     dc390_freeDCBs (host);
-    DC390_UNLOCK_ACB;
     DC390_UNLOCK_IO(host);
     scsi_unregister(host);
     return( 1 );
--- diff/drivers/scsi/tmscsim.h	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/tmscsim.h	2004-05-27 18:34:18.000000000 +0100
@@ -214,16 +214,12 @@
 PSRB		pTmpSRB;
 
 /* 0x2c: */
-ULONG		QueryCnt;
-struct list_head	cmdq;
-
-/* 0x38: */
 UCHAR		msgin123[4];
 UCHAR		DCBmap[MAX_SCSI_ID];
 UCHAR		Connected;
 UCHAR		pad;
 
-/* 0x3c: */
+/* 0x30: */
 #if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0)
 spinlock_t	lock;
 #endif
@@ -234,20 +230,20 @@
 UCHAR		Ignore_IRQ;	/* Not used */
 
 PDEVDECL1;			/* Pointer to PCI cfg. space */
-/* 0x4c/0x48: */
+/* 0x40/0x3c: */
 ULONG		Cmds;
 UINT		SelLost;
 UINT		SelConn;
 UINT		CmdInQ;
 UINT		CmdOutOfSRB;
 	
-/* 0x60/0x5c: */
+/* 0x54/0x50: */
 struct timer_list	Waiting_Timer;
-/* 0x74/0x70: */
+/* 0x68/0x64: */
 DC390_SRB	TmpSRB;
-/* 0xd8/0xd4: */
+/* 0xcc/0xc8: */
 DC390_SRB	SRB_array[MAX_SRB_CNT]; 	/* 50 SRBs */
-/* 0xfb0/0xfac: */
+/* 0xfa4/0xfa0: */
 };
 
 typedef  struct  _ACB	 DC390_ACB, *PACB;
@@ -406,16 +402,9 @@
  *	SISC query queue
  */
 typedef struct {
-	struct list_head	list;
 	dma_addr_t		saved_dma_handle;
 } dc390_cmd_scp_t;
 
-struct scsi_cmnd_list
-{
-	char dummy[offsetof(struct scsi_cmnd, SCp)];
-	dc390_cmd_scp_t scp;
-};
-
 /*
 **  Inquiry Data format
 */
--- diff/drivers/scsi/wd7000.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/wd7000.c	2004-05-27 18:34:18.000000000 +0100
@@ -165,6 +165,7 @@
  * Removed now obsolete wd7000.h
  */
 
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -846,7 +847,7 @@
 static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
 {
 	register Scb *scb, *p = NULL;
-	register unsigned long flags;
+	unsigned long flags;
 	register unsigned long timeout = jiffies + WAITnexttimeout;
 	register unsigned long now;
 	int i;
@@ -898,7 +899,7 @@
 
 static inline void free_scb(Scb * scb)
 {
-	register unsigned long flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&scbpool_lock, flags);
 
@@ -936,7 +937,7 @@
  */
 {
 	register int i, ogmb;
-	register unsigned long flags;
+	unsigned long flags;
 	unchar start_ogmb;
 	Mailbox *ogmbs = host->mb.ogmb;
 	int *next_ogmb = &(host->next_ogmb);
--- diff/drivers/serial/8250.c	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/8250.c	2004-05-27 18:34:18.000000000 +0100
@@ -832,7 +832,7 @@
 		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
 			tty->flip.work.func((void *)tty);
 			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-				return; // if TTY_DONT_FLIP is set
+				return;	/* if TTY_DONT_FLIP is set */
 		}
 		ch = serial_inp(up, UART_RX);
 		*tty->flip.char_buf_ptr = ch;
@@ -1193,12 +1193,21 @@
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
+#ifdef CONFIG_KGDB
+static int kgdb_irq = -1;
+#endif
+
 static int serial8250_startup(struct uart_port *port)
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
 	unsigned long flags;
 	int retval;
 
+#ifdef CONFIG_KGDB
+	if (up->port.irq == kgdb_irq)
+		return -EBUSY;
+#endif
+
 	up->capabilities = uart_config[up->port.type].flags;
 	up->mcr = 0;
 
@@ -1888,6 +1897,10 @@
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 
+#ifdef CONFIG_KGDB
+		if (up->port.irq == kgdb_irq)
+			up->port.kgdb = 1;
+#endif
 		up->port.line = i;
 		up->port.ops = &serial8250_pops;
 		init_timer(&up->timer);
@@ -2171,6 +2184,31 @@
 	uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
 }
 
+#ifdef CONFIG_KGDB
+/*
+ * Find all the ports using the given irq and shut them down.
+ * Result should be that the irq will be released.
+ */
+void shutdown_for_kgdb(struct async_struct * info)
+{
+        int irq = info->state->irq;
+        struct uart_8250_port *up;
+	int ttyS;
+
+	kgdb_irq = irq;			/* save for later init */
+	for (ttyS = 0; ttyS < UART_NR; ttyS++){
+		up =  &serial8250_ports[ttyS];
+		if (up->port.irq == irq && (irq_lists + irq)->head) {
+#ifdef CONFIG_DEBUG_SPINLOCK   /* ugly business... */
+			if(up->port.lock.magic != SPINLOCK_MAGIC)
+				spin_lock_init(&up->port.lock);
+#endif
+			serial8250_shutdown(&up->port);
+		}
+        }
+}
+#endif	/* CONFIG_KGDB */
+
 static int __init serial8250_init(void)
 {
 	int ret, i;
--- diff/drivers/serial/8250_acpi.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/serial/8250_acpi.c	2004-05-27 18:34:18.000000000 +0100
@@ -57,28 +57,18 @@
 static acpi_status acpi_serial_ext_irq(struct serial_struct *req,
 				       struct acpi_resource_ext_irq *ext_irq)
 {
-	if (ext_irq->number_of_interrupts > 0) {
-#ifdef CONFIG_IA64
-		req->irq = acpi_register_irq(ext_irq->interrupts[0],
-	                  ext_irq->active_high_low, ext_irq->edge_level);
-#else
-		req->irq = ext_irq->interrupts[0];
-#endif
-	}
+	if (ext_irq->number_of_interrupts > 0)
+		req->irq = acpi_register_gsi(ext_irq->interrupts[0],
+	                  ext_irq->edge_level, ext_irq->active_high_low);
 	return AE_OK;
 }
 
 static acpi_status acpi_serial_irq(struct serial_struct *req,
 				   struct acpi_resource_irq *irq)
 {
-	if (irq->number_of_interrupts > 0) {
-#ifdef CONFIG_IA64
-		req->irq = acpi_register_irq(irq->interrupts[0],
-	                  irq->active_high_low, irq->edge_level);
-#else
-		req->irq = irq->interrupts[0];
-#endif
-	}
+	if (irq->number_of_interrupts > 0)
+		req->irq = acpi_register_gsi(irq->interrupts[0],
+	                  irq->edge_level, irq->active_high_low);
 	return AE_OK;
 }
 
--- diff/drivers/serial/8250_hcdp.c	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/8250_hcdp.c	2004-05-27 18:34:18.000000000 +0100
@@ -96,7 +96,11 @@
 		 * of the entries for the same type device that has already
 		 * been parsed and initialized
 		 */
+#ifndef	CONFIG_KGDB_EARLY
 		if (hcdp_dev->type != HCDP_DEV_CONSOLE)
+#else
+		if (hcdp_dev->type != HCDP_DEV_CONSOLE && hcdp_dev->type != HCDP_DEV_DEBUG)
+#endif
 			continue;
 
 		iobase = ((u64) hcdp_dev->base_addr.addrhi << 32) |
@@ -183,16 +187,12 @@
 		}
 
 		if (HCDP_IRQ_SUPPORTED(hcdp_dev)) {
-#ifdef CONFIG_IA64
 			if (HCDP_PCI_UART(hcdp_dev))
-				port.irq = acpi_register_irq(gsi,
-					ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE);
+				port.irq = acpi_register_gsi(gsi,
+					ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
 			else
-				port.irq = acpi_register_irq(gsi,
-					ACPI_ACTIVE_HIGH, ACPI_EDGE_SENSITIVE);
-#else
-			port.irq = gsi;
-#endif
+				port.irq = acpi_register_gsi(gsi,
+					ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH);
 			port.flags |= UPF_AUTO_IRQ;
 
 			if (HCDP_PCI_UART(hcdp_dev))
@@ -205,6 +205,7 @@
 		 * Note: the above memset() initializes port.line to 0,
 		 * so we register this port as ttyS0.
 		 */
+		port.line = (hcdp_dev->type == HCDP_DEV_CONSOLE) ? 0 : 1;
 		if (early_serial_setup(&port) < 0) {
 			printk("setup_serial_hcdp(): early_serial_setup() "
 				"for HCDP serial console port failed. "
@@ -218,7 +219,9 @@
 				hcdp_dev->baud, hcdp_dev->bits);
 			add_preferred_console("ttyS", port.line, options);
 		}
+#ifndef	CONFIG_KGDB_EARLY
 		break;
+#endif
 	}
 
 #ifdef SERIAL_DEBUG_HCDP
--- diff/drivers/serial/8250_pnp.c	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/8250_pnp.c	2004-05-27 18:34:18.000000000 +0100
@@ -361,9 +361,6 @@
 			    ((port->min == 0x2f8) ||
 			     (port->min == 0x3f8) ||
 			     (port->min == 0x2e8) ||
-#ifdef CONFIG_X86_PC9800
-			     (port->min == 0x8b0) ||
-#endif
 			     (port->min == 0x3e8)))
 				return 1;
 	}
--- diff/drivers/serial/Kconfig	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/Kconfig	2004-05-27 18:34:18.000000000 +0100
@@ -517,19 +517,6 @@
 	depends on V850E_UART
 	select SERIAL_CORE_CONSOLE
 
-config SERIAL98
-	tristate "PC-9800 8251-based primary serial port support"
-	depends on X86_PC9800
-	select SERIAL_CORE
-	help
-	  If you want to use standard primary serial ports on PC-9800, 
-	  say Y.  Otherwise, say N.
-
-config SERIAL98_CONSOLE
-        bool "Support for console on PC-9800 standard serial port"
-        depends on SERIAL98=y
-	select SERIAL_CORE_CONSOLE
-
 config SERIAL_SH_SCI
 	tristate "SH SCI(F) serial port support"
 	depends on SUPERH || H8300
--- diff/drivers/serial/Makefile	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/Makefile	2004-05-27 18:34:18.000000000 +0100
@@ -33,7 +33,6 @@
 obj-$(CONFIG_SERIAL_68360) += 68360serial.o
 obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
 obj-$(CONFIG_V850E_UART) += v850e_uart.o
-obj-$(CONFIG_SERIAL98) += serial98.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
--- diff/drivers/serial/pxa.c	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/pxa.c	2004-05-27 18:34:18.000000000 +0100
@@ -33,7 +33,6 @@
 #include <linux/sysrq.h>
 #include <linux/serial_reg.h>
 #include <linux/circ_buf.h>
-#include <linux/serial.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
@@ -386,9 +385,6 @@
 	if (retval)
 		return retval;
 
-	CKEN |= up->cken;
-	udelay(1);
-
 	/*
 	 * Clear the FIFO buffers and disable them.
 	 * (they will be reenabled in set_termios())
@@ -461,8 +457,6 @@
 				  UART_FCR_CLEAR_RCVR |
 				  UART_FCR_CLEAR_XMIT);
 	serial_out(up, UART_FCR, 0);
-
-	CKEN &= ~up->cken;
 }
 
 static void
@@ -576,10 +570,14 @@
 serial_pxa_pm(struct uart_port *port, unsigned int state,
 	      unsigned int oldstate)
 {
+	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
 	if (state) {
 		/* sleep */
+		CKEN &= ~up->cken;
 	} else {
 		/* wake */
+		CKEN |= up->cken;
+		udelay(1);
 	}
 }
 
@@ -760,13 +758,12 @@
 	.cken	= CKEN6_FFUART,
 	.port	= {
 		.type		= PORT_PXA,
-		.iotype		= SERIAL_IO_MEM,
+		.iotype		= UPIO_MEM,
 		.membase	= (void *)&FFUART,
 		.mapbase	= __PREG(FFUART),
 		.irq		= IRQ_FFUART,
 		.uartclk	= 921600 * 16,
 		.fifosize	= 64,
-		.flags		= ASYNC_SKIP_TEST,
 		.ops		= &serial_pxa_pops,
 		.line		= 0,
 	},
@@ -775,13 +772,12 @@
 	.cken	= CKEN7_BTUART,
 	.port	= {
 		.type		= PORT_PXA,
-		.iotype		= SERIAL_IO_MEM,
+		.iotype		= UPIO_MEM,
 		.membase	= (void *)&BTUART,
 		.mapbase	= __PREG(BTUART),
 		.irq		= IRQ_BTUART,
 		.uartclk	= 921600 * 16,
 		.fifosize	= 64,
-		.flags		= ASYNC_SKIP_TEST,
 		.ops		= &serial_pxa_pops,
 		.line		= 1,
 	},
@@ -790,13 +786,12 @@
 	.cken	= CKEN5_STUART,
 	.port	= {
 		.type		= PORT_PXA,
-		.iotype		= SERIAL_IO_MEM,
+		.iotype		= UPIO_MEM,
 		.membase	= (void *)&STUART,
 		.mapbase	= __PREG(STUART),
 		.irq		= IRQ_STUART,
 		.uartclk	= 921600 * 16,
 		.fifosize	= 64,
-		.flags		= ASYNC_SKIP_TEST,
 		.ops		= &serial_pxa_pops,
 		.line		= 2,
 	},
@@ -830,6 +825,10 @@
 
 static void __exit serial_pxa_exit(void)
 {
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(serial_pxa_ports); i++)
+		uart_remove_one_port(&serial_pxa_reg, &serial_pxa_ports[i].port);
 	uart_unregister_driver(&serial_pxa_reg);
 }
 
--- diff/drivers/serial/serial_core.c	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/serial_core.c	2004-05-27 18:34:18.000000000 +0100
@@ -1985,6 +1985,11 @@
 {
 	unsigned int flags;
 
+#ifdef CONFIG_KGDB
+	if (port->kgdb)
+		return;
+#endif
+
 	/*
 	 * If there isn't a port here, don't do anything further.
 	 */
--- diff/drivers/usb/class/audio.c	2004-05-19 22:12:16.000000000 +0100
+++ source/drivers/usb/class/audio.c	2004-05-27 18:34:18.000000000 +0100
@@ -212,9 +212,6 @@
 
 #define dprintk(x)
 
-#undef abs
-extern int abs(int __x) __attribute_const__; /* Shut up warning */
-
 /* --------------------------------------------------------------------- */
 
 /*
@@ -398,17 +395,6 @@
 
 /* --------------------------------------------------------------------- */
 
-/* prevent picking up a bogus abs macro */
-#undef abs
-static inline int abs(int x)
-{
-        if (x < 0)
-		return -x;
-	return x;
-}
-                                
-/* --------------------------------------------------------------------- */
-
 static inline unsigned ld2(unsigned int x)
 {
 	unsigned r = 0;
--- diff/drivers/usb/class/usblp.c	2004-05-19 22:12:16.000000000 +0100
+++ source/drivers/usb/class/usblp.c	2004-05-27 18:34:18.000000000 +0100
@@ -226,11 +226,21 @@
 
 static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len)
 {
-	int retval = usb_control_msg(usblp->dev,
+	int retval;
+	int index = usblp->ifnum;
+
+	/* High byte has the interface index.
+	   Low byte has the alternate setting.
+	 */
+	if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) {
+	  index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting;
+	}
+
+	retval = usb_control_msg(usblp->dev,
 		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
-		request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT);
-	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d",
-		request, !!dir, recip, value, len, retval);
+		request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
+		request, !!dir, recip, value, index, len, retval);
 	return retval < 0 ? retval : 0;
 }
 
@@ -440,6 +450,9 @@
 		goto done;
 	}
 
+	dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
+		_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
+
 	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
 
 		switch (_IOC_NR(cmd)) {
--- diff/drivers/usb/core/Makefile	2004-05-19 22:12:16.000000000 +0100
+++ source/drivers/usb/core/Makefile	2004-05-27 18:34:18.000000000 +0100
@@ -3,7 +3,7 @@
 #
 
 usbcore-objs	:= usb.o hub.o hcd.o urb.o message.o \
-			config.o file.o buffer.o driverfs.o
+			config.o file.o buffer.o sysfs.o
 
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
--- diff/drivers/usb/core/config.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/usb/core/config.c	2004-05-27 18:34:18.000000000 +0100
@@ -465,23 +465,24 @@
 		goto err2;
 	memset(dev->rawdescriptors, 0, length);
 
-	buffer = kmalloc(8, GFP_KERNEL);
+	buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
 	if (!buffer)
 		goto err2;
 	desc = (struct usb_config_descriptor *)buffer;
 
 	for (cfgno = 0; cfgno < ncfg; cfgno++) {
-		/* We grab the first 8 bytes so we know how long the whole */
-		/* configuration is */
+		/* We grab just the first descriptor so we know how long
+		 * the whole configuration is */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
-		    buffer, 8);
+		    buffer, USB_DT_CONFIG_SIZE);
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
-			    "descriptor\n", cfgno);
+			    "descriptor/%s\n", cfgno, "start");
 			goto err;
-		} else if (result < 8) {
+		} else if (result < 4) {
 			dev_err(ddev, "config index %d descriptor too short "
-			    "(expected %i, got %i)\n", cfgno, 8, result);
+			    "(expected %i, got %i)\n", cfgno,
+			    USB_DT_CONFIG_SIZE, result);
 			result = -EINVAL;
 			goto err;
 		}
@@ -498,7 +499,7 @@
 		    bigbuffer, length);
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
-			    "descriptor\n", cfgno);
+			    "descriptor/%s\n", cfgno, "all");
 			kfree(bigbuffer);
 			goto err;
 		}
--- diff/drivers/usb/core/hcd.h	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/usb/core/hcd.h	2004-05-27 18:34:18.000000000 +0100
@@ -243,13 +243,13 @@
 extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
 					struct usb_bus *, unsigned port);
 extern int usb_new_device(struct usb_device *dev);
-extern void usb_choose_address(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
+extern void usb_choose_address(struct usb_device *dev);
+extern void usb_release_address(struct usb_device *dev);
 
 /* exported to hub driver ONLY to support usb_reset_device () */
 extern int usb_get_configuration(struct usb_device *dev);
 extern void usb_destroy_configuration(struct usb_device *dev);
-extern int usb_set_address(struct usb_device *dev);
 
 /* use these only before the device's address has been set */
 #define usb_snddefctrl(dev)		((PIPE_CONTROL << 30))
--- diff/drivers/usb/core/hub.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/usb/core/hub.c	2004-05-27 18:34:18.000000000 +0100
@@ -65,15 +65,15 @@
 #endif
 
 /* for dev_info, dev_dbg, etc */
-static inline struct device *hubdev (struct usb_device *dev)
+static inline struct device *hubdev (struct usb_device *hdev)
 {
-	return &dev->actconfig->interface[0]->dev;
+	return &hdev->actconfig->interface[0]->dev;
 }
 
 /* USB 2.0 spec Section 11.24.4.5 */
-static int get_hub_descriptor(struct usb_device *dev, void *data, int size)
+static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+	return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 		USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
 		USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT);
 }
@@ -81,27 +81,27 @@
 /*
  * USB 2.0 spec Section 11.24.2.1
  */
-static int clear_hub_feature(struct usb_device *dev, int feature)
+static int clear_hub_feature(struct usb_device *hdev, int feature)
 {
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 		USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
 }
 
 /*
  * USB 2.0 spec Section 11.24.2.2
  */
-static int clear_port_feature(struct usb_device *dev, int port, int feature)
+static int clear_port_feature(struct usb_device *hdev, int port, int feature)
 {
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
 }
 
 /*
  * USB 2.0 spec Section 11.24.2.13
  */
-static int set_port_feature(struct usb_device *dev, int port, int feature)
+static int set_port_feature(struct usb_device *hdev, int port, int feature)
 {
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 		USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
 }
 
@@ -110,16 +110,15 @@
  * for info about using port indicators
  */
 static void set_port_led(
-	struct usb_device *dev,
-	struct usb_hub *hub,
+	struct usb_device *hdev,
 	int port,
 	int selector
 )
 {
-	int status = set_port_feature(dev, (selector << 8) | port,
+	int status = set_port_feature(hdev, (selector << 8) | port,
 			USB_PORT_FEAT_INDICATOR);
 	if (status < 0)
-		dev_dbg (&hub->intf->dev,
+		dev_dbg (hubdev (hdev),
 			"port %d indicator %s status %d\n",
 			port,
 			({ char *s; switch (selector) {
@@ -137,12 +136,12 @@
 static void led_work (void *__hub)
 {
 	struct usb_hub		*hub = __hub;
-	struct usb_device	*dev = interface_to_usbdev (hub->intf);
+	struct usb_device	*hdev = interface_to_usbdev (hub->intf);
 	unsigned		i;
 	unsigned		changed = 0;
 	int			cursor = -1;
 
-	if (dev->state != USB_STATE_CONFIGURED)
+	if (hdev->state != USB_STATE_CONFIGURED)
 		return;
 
 	for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
@@ -189,13 +188,13 @@
 		}
 		if (selector != HUB_LED_AUTO)
 			changed = 1;
-		set_port_led(dev, hub, i + 1, selector);
+		set_port_led(hdev, i + 1, selector);
 		hub->indicator[i] = mode;
 	}
 	if (!changed && blinkenlights) {
 		cursor++;
 		cursor %= hub->descriptor->bNbrPorts;
-		set_port_led(dev, hub, cursor + 1, HUB_LED_GREEN);
+		set_port_led(hdev, cursor + 1, HUB_LED_GREEN);
 		hub->indicator[cursor] = INDICATOR_CYCLE;
 		changed++;
 	}
@@ -206,10 +205,10 @@
 /*
  * USB 2.0 spec Section 11.24.2.6
  */
-static int get_hub_status(struct usb_device *dev,
+static int get_hub_status(struct usb_device *hdev,
 		struct usb_hub_status *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+	return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
 		data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
 }
@@ -217,10 +216,10 @@
 /*
  * USB 2.0 spec Section 11.24.2.7
  */
-static int get_port_status(struct usb_device *dev, int port,
+static int get_port_status(struct usb_device *hdev, int port,
 		struct usb_port_status *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+	return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
 		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
 		data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
 }
@@ -278,9 +277,9 @@
 
 /* USB 2.0 spec Section 11.24.2.3 */
 static inline int
-hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt)
+hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
 {
-	return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0),
+	return usb_control_msg (hdev, usb_rcvctrlpipe (hdev, 0),
 		HUB_CLEAR_TT_BUFFER, USB_RT_PORT,
 		devinfo, tt, 0, 0, HZ);
 }
@@ -300,7 +299,7 @@
 	while (!list_empty (&hub->tt.clear_list)) {
 		struct list_head	*temp;
 		struct usb_tt_clear	*clear;
-		struct usb_device	*dev;
+		struct usb_device	*hdev;
 		int			status;
 
 		temp = hub->tt.clear_list.next;
@@ -309,12 +308,13 @@
 
 		/* drop lock so HCD can concurrently report other TT errors */
 		spin_unlock_irqrestore (&hub->tt.lock, flags);
-		dev = interface_to_usbdev (hub->intf);
-		status = hub_clear_tt_buffer (dev, clear->devinfo, clear->tt);
+		hdev = interface_to_usbdev (hub->intf);
+		status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
 		spin_lock_irqsave (&hub->tt.lock, flags);
 
 		if (status)
-			dev_err (&dev->dev, "clear tt %d (%04x) error %d\n",
+			dev_err (&hdev->dev,
+				"clear tt %d (%04x) error %d\n",
 				clear->tt, clear->devinfo, status);
 		kfree (clear);
 	}
@@ -334,9 +334,9 @@
  * It may not be possible for that hub to handle additional full (or low)
  * speed transactions until that state is fully cleared out.
  */
-void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
+void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
 {
-	struct usb_tt		*tt = dev->tt;
+	struct usb_tt		*tt = udev->tt;
 	unsigned long		flags;
 	struct usb_tt_clear	*clear;
 
@@ -345,15 +345,15 @@
 	 * there can be many TTs per hub).  even if they're uncommon.
 	 */
 	if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) {
-		dev_err (&dev->dev, "can't save CLEAR_TT_BUFFER state\n");
+		dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
 		/* FIXME recover somehow ... RESET_TT? */
 		return;
 	}
 
 	/* info that CLEAR_TT_BUFFER needs */
-	clear->tt = tt->multi ? dev->ttport : 1;
+	clear->tt = tt->multi ? udev->ttport : 1;
 	clear->devinfo = usb_pipeendpoint (pipe);
-	clear->devinfo |= dev->devnum << 4;
+	clear->devinfo |= udev->devnum << 4;
 	clear->devinfo |= usb_pipecontrol (pipe)
 			? (USB_ENDPOINT_XFER_CONTROL << 11)
 			: (USB_ENDPOINT_XFER_BULK << 11);
@@ -369,15 +369,15 @@
 
 static void hub_power_on(struct usb_hub *hub)
 {
-	struct usb_device *dev;
+	struct usb_device *hdev;
 	int i;
 
 	/* if hub supports power switching, enable power on each port */
 	if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
 		dev_dbg(&hub->intf->dev, "enabling power on all ports\n");
-		dev = interface_to_usbdev(hub->intf);
+		hdev = interface_to_usbdev(hub->intf);
 		for (i = 0; i < hub->descriptor->bNbrPorts; i++)
-			set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+			set_port_feature(hdev, i + 1, USB_PORT_FEAT_POWER);
 	}
 
 	/* Wait for power to be enabled */
@@ -387,12 +387,12 @@
 static int hub_hub_status(struct usb_hub *hub,
 		u16 *status, u16 *change)
 {
-	struct usb_device *dev = interface_to_usbdev (hub->intf);
+	struct usb_device *hdev = interface_to_usbdev (hub->intf);
 	int ret;
 
-	ret = get_hub_status(dev, &hub->status->hub);
+	ret = get_hub_status(hdev, &hub->status->hub);
 	if (ret < 0)
-		dev_err (hubdev (dev),
+		dev_err (&hub->intf->dev,
 			"%s failed (err = %d)\n", __FUNCTION__, ret);
 	else {
 		*status = le16_to_cpu(hub->status->hub.wHubStatus);
@@ -405,14 +405,14 @@
 static int hub_configure(struct usb_hub *hub,
 	struct usb_endpoint_descriptor *endpoint)
 {
-	struct usb_device *dev = interface_to_usbdev (hub->intf);
-	struct device *hub_dev;
+	struct usb_device *hdev = interface_to_usbdev (hub->intf);
+	struct device *hub_dev = &hub->intf->dev;
 	u16 hubstatus, hubchange;
 	unsigned int pipe;
 	int maxp, ret;
 	char *message;
 
-	hub->buffer = usb_buffer_alloc(dev, sizeof(*hub->buffer), GFP_KERNEL,
+	hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
 			&hub->buffer_dma);
 	if (!hub->buffer) {
 		message = "can't allocate hub irq buffer";
@@ -438,7 +438,7 @@
 	 * hub->descriptor can handle USB_MAXCHILDREN ports,
 	 * but the hub can/will return fewer bytes here.
 	 */
-	ret = get_hub_descriptor(dev, hub->descriptor,
+	ret = get_hub_descriptor(hdev, hub->descriptor,
 			sizeof(*hub->descriptor));
 	if (ret < 0) {
 		message = "can't read hub descriptor";
@@ -449,10 +449,9 @@
 		goto fail;
 	}
 
-	hub_dev = hubdev(dev);
-	dev->maxchild = hub->descriptor->bNbrPorts;
-	dev_info (hub_dev, "%d port%s detected\n", dev->maxchild,
-		(dev->maxchild == 1) ? "" : "s");
+	hdev->maxchild = hub->descriptor->bNbrPorts;
+	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
+		(hdev->maxchild == 1) ? "" : "s");
 
 	le16_to_cpus(&hub->descriptor->wHubCharacteristics);
 
@@ -460,11 +459,11 @@
 		int	i;
 		char	portstr [USB_MAXCHILDREN + 1];
 
-		for (i = 0; i < dev->maxchild; i++)
+		for (i = 0; i < hdev->maxchild; i++)
 			portstr[i] = hub->descriptor->DeviceRemovable
 				    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
 				? 'F' : 'R';
-		portstr[dev->maxchild] = 0;
+		portstr[hdev->maxchild] = 0;
 		dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);
 	} else
 		dev_dbg(hub_dev, "standalone hub\n");
@@ -498,32 +497,32 @@
 	spin_lock_init (&hub->tt.lock);
 	INIT_LIST_HEAD (&hub->tt.clear_list);
 	INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub);
-	switch (dev->descriptor.bDeviceProtocol) {
+	switch (hdev->descriptor.bDeviceProtocol) {
 		case 0:
 			break;
 		case 1:
 			dev_dbg(hub_dev, "Single TT\n");
-			hub->tt.hub = dev;
+			hub->tt.hub = hdev;
 			break;
 		case 2:
-			ret = usb_set_interface(dev, 0, 1);
+			ret = usb_set_interface(hdev, 0, 1);
 			if (ret == 0) {
 				dev_dbg(hub_dev, "TT per port\n");
 				hub->tt.multi = 1;
 			} else
 				dev_err(hub_dev, "Using single TT (err %d)\n",
 					ret);
-			hub->tt.hub = dev;
+			hub->tt.hub = hdev;
 			break;
 		default:
 			dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
-				dev->descriptor.bDeviceProtocol);
+				hdev->descriptor.bDeviceProtocol);
 			break;
 	}
 
 	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
 		case 0x00:
-			if (dev->descriptor.bDeviceProtocol != 0)
+			if (hdev->descriptor.bDeviceProtocol != 0)
 				dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n");
 			break;
 		case 0x20:
@@ -549,9 +548,9 @@
 	/* power budgeting mostly matters with bus-powered hubs,
 	 * and battery-powered root hubs (may provide just 8 mA).
 	 */
-	ret = usb_get_status(dev, USB_RECIP_DEVICE, 0, &hubstatus);
+	ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
 	if (ret < 0) {
-		message = "can't get hubdev status";
+		message = "can't get hub status";
 		goto fail;
 	}
 	cpu_to_le16s(&hubstatus);
@@ -572,7 +571,7 @@
 	}
 
 	/* local power status reports aren't always correct */
-	if (dev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)
+	if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)
 		dev_dbg(hub_dev, "local power source is %s\n",
 			(hubstatus & HUB_STATUS_LOCAL_POWER)
 			? "lost (inactive)" : "good");
@@ -582,8 +581,8 @@
 			(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
 
 	/* Start the interrupt endpoint */
-	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+	pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
 
 	if (maxp > sizeof(*hub->buffer))
 		maxp = sizeof(*hub->buffer);
@@ -595,7 +594,7 @@
 		goto fail;
 	}
 
-	usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq,
+	usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
 		hub, endpoint->bInterval);
 	hub->urb->transfer_dma = hub->buffer_dma;
 	hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -611,7 +610,7 @@
 
 	/* maybe start cycling the hub leds */
 	if (hub->has_indicators && blinkenlights) {
-		set_port_led(dev, hub, 1, HUB_LED_GREEN);
+		set_port_led(hdev, 1, HUB_LED_GREEN);
 		hub->indicator [0] = INDICATOR_CYCLE;
 		schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
 	}
@@ -621,7 +620,7 @@
 	return 0;
 
 fail:
-	dev_err (&hub->intf->dev, "config failed, %s (err %d)\n",
+	dev_err (hub_dev, "config failed, %s (err %d)\n",
 			message, ret);
 	/* hub_disconnect() frees urb and descriptor */
 	return ret;
@@ -693,19 +692,21 @@
 {
 	struct usb_host_interface *desc;
 	struct usb_endpoint_descriptor *endpoint;
-	struct usb_device *dev;
+	struct usb_device *hdev;
 	struct usb_hub *hub;
+	struct device *hub_dev;
 	unsigned long flags;
 
 	desc = intf->cur_altsetting;
-	dev = interface_to_usbdev(intf);
+	hdev = interface_to_usbdev(intf);
+	hub_dev = &intf->dev;
 
 	/* Some hubs have a subclass of 1, which AFAICT according to the */
 	/*  specs is not defined, but it works */
 	if ((desc->desc.bInterfaceSubClass != 0) &&
 	    (desc->desc.bInterfaceSubClass != 1)) {
 descriptor_error:
-		dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
+		dev_err (hub_dev, "bad descriptor, ignoring hub\n");
 		return -EIO;
 	}
 
@@ -729,11 +730,11 @@
 	}
 
 	/* We found a hub */
-	dev_info (hubdev (dev), "USB hub found\n");
+	dev_info (hub_dev, "USB hub found\n");
 
 	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
 	if (!hub) {
-		dev_dbg (hubdev(dev), "couldn't kmalloc hub struct\n");
+		dev_dbg (hub_dev, "couldn't kmalloc hub struct\n");
 		return -ENOMEM;
 	}
 
@@ -752,7 +753,7 @@
 
 	usb_set_intfdata (intf, hub);
 
-	if (dev->speed == USB_SPEED_HIGH)
+	if (hdev->speed == USB_SPEED_HIGH)
 		highspeed_hubs++;
 
 	if (hub_configure(hub, endpoint) >= 0)
@@ -765,7 +766,7 @@
 static int
 hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 {
-	struct usb_device *hub = interface_to_usbdev (intf);
+	struct usb_device *hdev = interface_to_usbdev (intf);
 
 	/* assert ifno == 0 (part of hub spec) */
 	switch (code) {
@@ -775,16 +776,16 @@
 		int i;
 
 		spin_lock_irqsave(&hub_event_lock, flags);
-		if (hub->devnum <= 0)
+		if (hdev->devnum <= 0)
 			info->nports = 0;
 		else {
-			info->nports = hub->maxchild;
+			info->nports = hdev->maxchild;
 			for (i = 0; i < info->nports; i++) {
-				if (hub->children[i] == NULL)
+				if (hdev->children[i] == NULL)
 					info->port[i] = 0;
 				else
 					info->port[i] =
-						hub->children[i]->devnum;
+						hdev->children[i]->devnum;
 			}
 		}
 		spin_unlock_irqrestore(&hub_event_lock, flags);
@@ -799,13 +800,13 @@
 
 static int hub_reset(struct usb_hub *hub)
 {
-	struct usb_device *dev = interface_to_usbdev(hub->intf);
+	struct usb_device *hdev = interface_to_usbdev(hub->intf);
 	int i;
 
 	/* Disconnect any attached devices */
 	for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
-		if (dev->children[i])
-			usb_disconnect(&dev->children[i]);
+		if (hdev->children[i])
+			usb_disconnect(&hdev->children[i]);
 	}
 
 	/* Attempt to reset the hub */
@@ -814,10 +815,10 @@
 	else
 		return -1;
 
-	if (usb_reset_device(dev))
+	if (usb_reset_device(hdev))
 		return -1;
 
-	hub->urb->dev = dev;                                                    
+	hub->urb->dev = hdev;                                                    
 	if (usb_submit_urb(hub->urb, GFP_KERNEL))
 		return -1;
 
@@ -826,36 +827,36 @@
 	return 0;
 }
 
-static void hub_start_disconnect(struct usb_device *dev)
+static void hub_start_disconnect(struct usb_device *hdev)
 {
-	struct usb_device *parent = dev->parent;
+	struct usb_device *parent = hdev->parent;
 	int i;
 
 	/* Find the device pointer to disconnect */
 	if (parent) {
 		for (i = 0; i < parent->maxchild; i++) {
-			if (parent->children[i] == dev) {
+			if (parent->children[i] == hdev) {
 				usb_disconnect(&parent->children[i]);
 				return;
 			}
 		}
 	}
 
-	dev_err(&dev->dev, "cannot disconnect hub!\n");
+	dev_err(&hdev->dev, "cannot disconnect hub!\n");
 }
 
-static int hub_port_status(struct usb_device *dev, int port,
+static int hub_port_status(struct usb_device *hdev, int port,
 			       u16 *status, u16 *change)
 {
-	struct usb_hub *hub = usb_get_intfdata(dev->actconfig->interface[0]);
+	struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]);
 	int ret;
 
 	if (!hub)
 		return -ENODEV;
 
-	ret = get_port_status(dev, port + 1, &hub->status->port);
+	ret = get_port_status(hdev, port + 1, &hub->status->port);
 	if (ret < 0)
-		dev_err (hubdev (dev),
+		dev_err (&hub->intf->dev,
 			"%s failed (err = %d)\n", __FUNCTION__, ret);
 	else {
 		*status = le16_to_cpu(hub->status->port.wPortStatus);
@@ -876,8 +877,8 @@
 #define HUB_RESET_TIMEOUT	500
 
 /* return: -1 on error, 0 on success, 1 on disconnect.  */
-static int hub_port_wait_reset(struct usb_device *hub, int port,
-				struct usb_device *dev, unsigned int delay)
+static int hub_port_wait_reset(struct usb_device *hdev, int port,
+				struct usb_device *udev, unsigned int delay)
 {
 	int delay_time, ret;
 	u16 portstatus;
@@ -890,7 +891,7 @@
 		msleep(delay);
 
 		/* read and decode port status */
-		ret = hub_port_status(hub, port, &portstatus, &portchange);
+		ret = hub_port_status(hdev, port, &portstatus, &portchange);
 		if (ret < 0) {
 			return -1;
 		}
@@ -907,11 +908,11 @@
 		if (!(portstatus & USB_PORT_STAT_RESET) &&
 		    (portstatus & USB_PORT_STAT_ENABLE)) {
 			if (portstatus & USB_PORT_STAT_HIGH_SPEED)
-				dev->speed = USB_SPEED_HIGH;
+				udev->speed = USB_SPEED_HIGH;
 			else if (portstatus & USB_PORT_STAT_LOW_SPEED)
-				dev->speed = USB_SPEED_LOW;
+				udev->speed = USB_SPEED_LOW;
 			else
-				dev->speed = USB_SPEED_FULL;
+				udev->speed = USB_SPEED_FULL;
 			return 0;
 		}
 
@@ -919,7 +920,7 @@
 		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
 			delay = HUB_LONG_RESET_TIME;
 
-		dev_dbg (hubdev (hub),
+		dev_dbg (hubdev (hdev),
 			"port %d not reset yet, waiting %dms\n",
 			port + 1, delay);
 	}
@@ -928,46 +929,47 @@
 }
 
 /* return: -1 on error, 0 on success, 1 on disconnect.  */
-static int hub_port_reset(struct usb_device *hub, int port,
-				struct usb_device *dev, unsigned int delay)
+static int hub_port_reset(struct usb_device *hdev, int port,
+				struct usb_device *udev, unsigned int delay)
 {
 	int i, status;
+	struct device *hub_dev = hubdev (hdev);
 
 	/* Reset the port */
 	for (i = 0; i < PORT_RESET_TRIES; i++) {
-		set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
+		set_port_feature(hdev, port + 1, USB_PORT_FEAT_RESET);
 
 		/* return on disconnect or reset */
-		status = hub_port_wait_reset(hub, port, dev, delay);
+		status = hub_port_wait_reset(hdev, port, udev, delay);
 		if (status != -1) {
-			clear_port_feature(hub,
+			clear_port_feature(hdev,
 				port + 1, USB_PORT_FEAT_C_RESET);
-			dev->state = status
+			udev->state = status
 					? USB_STATE_NOTATTACHED
 					: USB_STATE_DEFAULT;
 			return status;
 		}
 
-		dev_dbg (hubdev (hub),
+		dev_dbg (hub_dev,
 			"port %d not enabled, trying reset again...\n",
 			port + 1);
 		delay = HUB_LONG_RESET_TIME;
 	}
 
-	dev_err (hubdev (hub),
+	dev_err (hub_dev,
 		"Cannot enable port %i.  Maybe the USB cable is bad?\n",
 		port + 1);
 
 	return -1;
 }
 
-static int hub_port_disable(struct usb_device *hub, int port)
+static int hub_port_disable(struct usb_device *hdev, int port)
 {
 	int ret;
 
-	ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
+	ret = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_ENABLE);
 	if (ret)
-		dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n",
+		dev_err(hubdev(hdev), "cannot disable port %d (err = %d)\n",
 			port + 1, ret);
 
 	return ret;
@@ -992,7 +994,7 @@
 #define HUB_DEBOUNCE_STABLE	  4
 
 /* return: -1 on error, 0 on success, 1 on disconnect.  */
-static int hub_port_debounce(struct usb_device *hub, int port)
+static int hub_port_debounce(struct usb_device *hdev, int port)
 {
 	int ret;
 	int delay_time, stable_count;
@@ -1004,7 +1006,7 @@
 	for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
 		msleep(HUB_DEBOUNCE_STEP);
 
-		ret = hub_port_status(hub, port, &portstatus, &portchange);
+		ret = hub_port_status(hdev, port, &portstatus, &portchange);
 		if (ret < 0)
 			return -1;
 
@@ -1019,17 +1021,34 @@
 		connection = portstatus & USB_PORT_STAT_CONNECTION;
 
 		if ((portchange & USB_PORT_STAT_C_CONNECTION)) {
-			clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION);
+			clear_port_feature(hdev, port+1, USB_PORT_FEAT_C_CONNECTION);
 		}
 	}
 
-	dev_dbg (hubdev (hub),
+	dev_dbg (hubdev (hdev),
 		"debounce: port %d: delay %dms stable %d status 0x%x\n",
 		port + 1, delay_time, stable_count, portstatus);
 
 	return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
 }
 
+static int hub_set_address(struct usb_device *udev)
+{
+	int retval;
+
+	if (udev->devnum == 0)
+		return -EINVAL;
+	if (udev->state != USB_STATE_DEFAULT &&
+			udev->state != USB_STATE_ADDRESS)
+		return -EINVAL;
+	retval = usb_control_msg(udev, usb_snddefctrl(udev),
+		USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+		NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+	if (retval == 0)
+		udev->state = USB_STATE_ADDRESS;
+	return retval;
+}
+
 /* reset device, (re)assign address, get device descriptor.
  * device connection is stable, no more debouncing needed.
  * returns device in USB_STATE_ADDRESS, except on error.
@@ -1039,18 +1058,18 @@
  * config changes and disconnect processing.
  */
 static int
-hub_port_init (struct usb_device *hub, struct usb_device *dev, int port)
+hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port)
 {
 	static DECLARE_MUTEX(usb_address0_sem);
 
 	int			i, j, retval = -ENODEV;
 	unsigned		delay = HUB_SHORT_RESET_TIME;
-	enum usb_device_speed	oldspeed = dev->speed;
+	enum usb_device_speed	oldspeed = udev->speed;
 
 	/* root hub ports have a slightly longer reset period
 	 * (from USB 2.0 spec, section 7.1.7.5)
 	 */
-	if (!hub->parent)
+	if (!hdev->parent)
 		delay = HUB_ROOT_RESET_TIME;
 
 	/* Some low speed devices have problems with the quick delay, so */
@@ -1061,7 +1080,7 @@
 	down(&usb_address0_sem);
 
 	/* Reset the device; full speed may morph to high speed */
-	switch (hub_port_reset(hub, port, dev, delay)) {
+	switch (hub_port_reset(hdev, port, udev, delay)) {
 	case 0:			/* success, speed is known */
 		break;
 	case 1:			/* disconnect, give to companion */
@@ -1070,15 +1089,15 @@
 	default:		/* error */
 		goto fail;
 	}
-	if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != dev->speed) {
-		dev_dbg(&dev->dev, "device reset changed speed!\n");
+	if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
+		dev_dbg(&udev->dev, "device reset changed speed!\n");
 		goto fail;
 	}
   
 	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 	 * it's fixed size except for full speed devices.
 	 */
-	switch (dev->speed) {
+	switch (udev->speed) {
 	case USB_SPEED_HIGH:		/* fixed at 64 */
 		i = 64;
 		break;
@@ -1094,43 +1113,43 @@
 	default:
 		goto fail;
 	}
-	dev->epmaxpacketin [0] = i;
-	dev->epmaxpacketout[0] = i;
+	udev->epmaxpacketin [0] = i;
+	udev->epmaxpacketout[0] = i;
  
 	/* set the address */
-	if (dev->devnum <= 0) {
-		usb_choose_address(dev);
-		if (dev->devnum <= 0)
+	if (udev->devnum <= 0) {
+		usb_choose_address(udev);
+		if (udev->devnum <= 0)
 			goto fail;
 
 		/* Set up TT records, if needed  */
-		if (hub->tt) {
-			dev->tt = hub->tt;
-			dev->ttport = hub->ttport;
-		} else if (dev->speed != USB_SPEED_HIGH
-				&& hub->speed == USB_SPEED_HIGH) {
-			struct usb_hub	*hubstate;
+		if (hdev->tt) {
+			udev->tt = hdev->tt;
+			udev->ttport = hdev->ttport;
+		} else if (udev->speed != USB_SPEED_HIGH
+				&& hdev->speed == USB_SPEED_HIGH) {
+			struct usb_hub	*hub;
  
-			hubstate = usb_get_intfdata (hub->actconfig
+			hub = usb_get_intfdata (hdev->actconfig
 							->interface[0]);
-			dev->tt = &hubstate->tt;
-			dev->ttport = port + 1;
+			udev->tt = &hub->tt;
+			udev->ttport = port + 1;
 		}
 
 		/* force the right log message (below) at low speed */
 		oldspeed = USB_SPEED_UNKNOWN;
 	}
  
-	dev_info (&dev->dev,
+	dev_info (&udev->dev,
 			"%s %s speed USB device using address %d\n",
 			(oldspeed == USB_SPEED_UNKNOWN) ? "new" : "reset",
-			({ char *speed; switch (dev->speed) {
+			({ char *speed; switch (udev->speed) {
 			case USB_SPEED_LOW:	speed = "low";	break;
 			case USB_SPEED_FULL:	speed = "full";	break;
 			case USB_SPEED_HIGH:	speed = "high";	break;
 			default: 		speed = "?";	break;
 			}; speed;}),
-			dev->devnum);
+			udev->devnum);
  
 	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
 	 * Because device hardware and firmware is sometimes buggy in
@@ -1143,20 +1162,19 @@
 	 */
 	for (i = 0; i < GET_DESCRIPTOR_TRIES; ++i) {
 		for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-			retval = usb_set_address(dev);
+			retval = hub_set_address(udev);
 			if (retval >= 0)
 				break;
 			msleep(200);
 		}
 		if (retval < 0) {
-			dev_err(&dev->dev,
+			dev_err(&udev->dev,
 				"device not accepting address %d, error %d\n",
-				dev->devnum, retval);
+				udev->devnum, retval);
  fail:
-			hub_port_disable(hub, port);
-			clear_bit(dev->devnum, dev->bus->devmap.devicemap);
-			dev->devnum = -1;
-			usb_put_dev(dev);
+			hub_port_disable(hdev, port);
+			usb_release_address(udev);
+			usb_put_dev(udev);
 			up(&usb_address0_sem);
 			return retval;
 		}
@@ -1166,31 +1184,31 @@
 		 *  - read ep0 maxpacket even for high and low speed,
   		 */
 		msleep(10);
-		retval = usb_get_device_descriptor(dev, 8);
+		retval = usb_get_device_descriptor(udev, 8);
 		if (retval >= 8)
 			break;
 		msleep(100);
 	}
 	if (retval != 8) {
-		dev_err(&dev->dev, "device descriptor read/%s, error %d\n",
+		dev_err(&udev->dev, "device descriptor read/%s, error %d\n",
 				"8", retval);
 		if (retval >= 0)
 			retval = -EMSGSIZE;
 		goto fail;
 	}
-	if (dev->speed == USB_SPEED_FULL
-			&& (dev->epmaxpacketin [0]
-				!= dev->descriptor.bMaxPacketSize0)) {
-		usb_disable_endpoint(dev, 0);
-		usb_endpoint_running(dev, 0, 1);
-		usb_endpoint_running(dev, 0, 0);
-		dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
-		dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+	if (udev->speed == USB_SPEED_FULL
+			&& (udev->epmaxpacketin [0]
+				!= udev->descriptor.bMaxPacketSize0)) {
+		usb_disable_endpoint(udev, 0);
+		usb_endpoint_running(udev, 0, 1);
+		usb_endpoint_running(udev, 0, 0);
+		udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0;
+		udev->epmaxpacketout[0] = udev->descriptor.bMaxPacketSize0;
 	}
   
-	retval = usb_get_device_descriptor(dev, USB_DT_DEVICE_SIZE);
-	if (retval < (signed)sizeof(dev->descriptor)) {
-		dev_err(&dev->dev, "device descriptor read/%s, error %d\n",
+	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
+	if (retval < (signed)sizeof(udev->descriptor)) {
+		dev_err(&udev->dev, "device descriptor read/%s, error %d\n",
 			"all", retval);
 		if (retval >= 0)
 			retval = -ENOMSG;
@@ -1198,14 +1216,14 @@
 	}
 
 	/* now dev is visible to other tasks */
-	hub->children[port] = dev;
+	hdev->children[port] = udev;
 
 	up(&usb_address0_sem);
 	return 0;
 }
 
 static void
-check_highspeed (struct usb_hub *hub, struct usb_device *dev, int port)
+check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port)
 {
 	struct usb_qualifier_descriptor	*qual;
 	int				status;
@@ -1214,10 +1232,10 @@
 	if (qual == 0)
 		return;
 
-	status = usb_get_descriptor (dev, USB_DT_DEVICE_QUALIFIER, 0,
+	status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0,
 			qual, sizeof *qual);
 	if (status == sizeof *qual) {
-		dev_info(&dev->dev, "not running at top speed; "
+		dev_info(&udev->dev, "not running at top speed; "
 			"connect to a high speed hub\n");
 		/* hub LEDs are probably harder to miss than syslog */
 		if (hub->has_indicators) {
@@ -1229,31 +1247,31 @@
 }
 
 static unsigned
-hub_power_remaining (struct usb_hub *hubstate, struct usb_device *hub)
+hub_power_remaining (struct usb_hub *hub, struct usb_device *hdev)
 {
 	int remaining;
 	unsigned i;
 
-	remaining = hubstate->power_budget;
+	remaining = hub->power_budget;
 	if (!remaining)		/* self-powered */
 		return 0;
 
-	for (i = 0; i < hub->maxchild; i++) {
-		struct usb_device	*dev = hub->children[i];
+	for (i = 0; i < hdev->maxchild; i++) {
+		struct usb_device	*udev = hdev->children[i];
 		int			delta;
 
-		if (!dev)
+		if (!udev)
 			continue;
 
-		if (dev->actconfig)
-			delta = dev->actconfig->desc.bMaxPower;
+		if (udev->actconfig)
+			delta = udev->actconfig->desc.bMaxPower;
 		else
 			delta = 50;
-		// dev_dbg(&dev->dev, "budgeted %dmA\n", 2 * delta);
+		// dev_dbg(&udev->dev, "budgeted %dmA\n", 2 * delta);
 		remaining -= delta;
 	}
 	if (remaining < 0) {
-		dev_warn(&hubstate->intf->dev,
+		dev_warn(&hub->intf->dev,
 			"%dmA over power budget!\n",
 			-2 * remaining);
 		remaining = 0;
@@ -1261,72 +1279,73 @@
 	return remaining;
 }
  
-static void hub_port_connect_change(struct usb_hub *hubstate, int port,
+static void hub_port_connect_change(struct usb_hub *hub, int port,
 					u16 portstatus, u16 portchange)
 {
-	struct usb_device *hub = interface_to_usbdev(hubstate->intf);
+	struct usb_device *hdev = interface_to_usbdev(hub->intf);
+	struct device *hub_dev = &hub->intf->dev;
 	int status, i;
  
-	dev_dbg (&hubstate->intf->dev,
+	dev_dbg (hub_dev,
 		"port %d, status %04x, change %04x, %s\n",
 		port + 1, portstatus, portchange, portspeed (portstatus));
  
 	/* Clear the connection change status */
-	clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
+	clear_port_feature(hdev, port + 1, USB_PORT_FEAT_C_CONNECTION);
 
-	if (hubstate->has_indicators) {
-		set_port_led(hub, hubstate, port + 1, HUB_LED_AUTO);
-		hubstate->indicator[port] = INDICATOR_AUTO;
+	if (hub->has_indicators) {
+		set_port_led(hdev, port + 1, HUB_LED_AUTO);
+		hub->indicator[port] = INDICATOR_AUTO;
 	}
  
 	/* Disconnect any existing devices under this port */
-	if (hub->children[port])
-		usb_disconnect(&hub->children[port]);
+	if (hdev->children[port])
+		usb_disconnect(&hdev->children[port]);
 
 	/* Return now if nothing is connected */
 	if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
 
 		/* maybe switch power back on (e.g. root hub was reset) */
-		if ((hubstate->descriptor->wHubCharacteristics
+		if ((hub->descriptor->wHubCharacteristics
 					& HUB_CHAR_LPSM) < 2
 				&& !(portstatus & (1 << USB_PORT_FEAT_POWER)))
-			set_port_feature(hub, port + 1, USB_PORT_FEAT_POWER);
+			set_port_feature(hdev, port + 1, USB_PORT_FEAT_POWER);
  
 		if (portstatus & USB_PORT_STAT_ENABLE)
   			goto done;
 		return;
 	}
   
-	if (hub_port_debounce(hub, port)) {
-		dev_err (&hubstate->intf->dev,
+	if (hub_port_debounce(hdev, port)) {
+		dev_err (hub_dev,
 			"connect-debounce failed, port %d disabled\n",
 			port+1);
 		goto done;
 	}
 
 	for (i = 0; i < SET_CONFIG_TRIES; i++) {
-		struct usb_device *dev;
+		struct usb_device *udev;
 
 		/* reallocate for each attempt, since references
 		 * to the previous one can escape in various ways
 		 */
-		dev = usb_alloc_dev(hub, hub->bus, port);
-		if (!dev) {
-			dev_err (&hubstate->intf->dev,
+		udev = usb_alloc_dev(hdev, hdev->bus, port);
+		if (!udev) {
+			dev_err (hub_dev,
 				"couldn't allocate port %d usb_device\n", port+1);
 			goto done;
 		}
-		dev->state = USB_STATE_POWERED;
+		udev->state = USB_STATE_POWERED;
 	  
 		/* hub can tell if it's lowspeed already:  D- pullup (not D+) */
 		if (portstatus & USB_PORT_STAT_LOW_SPEED)
-			dev->speed = USB_SPEED_LOW;
+			udev->speed = USB_SPEED_LOW;
 		else
-			dev->speed = USB_SPEED_UNKNOWN;
+			udev->speed = USB_SPEED_UNKNOWN;
 
 		/* reset, set address, get descriptor, add to hub's children */
-		down (&dev->serialize);
-		status = hub_port_init(hub, dev, port);
+		down (&udev->serialize);
+		status = hub_port_init(hdev, udev, port);
 		if (status == -EBUSY)
 			break;
 		if (status < 0)
@@ -1338,50 +1357,50 @@
 		 * (without reading syslog), even without per-port LEDs
 		 * on the parent.
 		 */
-		if (dev->descriptor.bDeviceClass == USB_CLASS_HUB
-				&& hubstate->power_budget) {
+		if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
+				&& hub->power_budget) {
 			u16	devstat;
 
-			status = usb_get_status(dev, USB_RECIP_DEVICE, 0,
+			status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
 					&devstat);
 			if (status < 0) {
-				dev_dbg(&dev->dev, "get status %d ?\n", status);
+				dev_dbg(&udev->dev, "get status %d ?\n", status);
 				continue;
 			}
 			cpu_to_le16s(&devstat);
 			if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
-				dev_err(&dev->dev,
+				dev_err(&udev->dev,
 					"can't connect bus-powered hub "
 					"to this port\n");
-				if (hubstate->has_indicators) {
-					hubstate->indicator[port] =
+				if (hub->has_indicators) {
+					hub->indicator[port] =
 						INDICATOR_AMBER_BLINK;
-					schedule_work (&hubstate->leds);
+					schedule_work (&hub->leds);
 				}
-				hub->children[port] = NULL;
-				usb_put_dev(dev);
-				hub_port_disable(hub, port);
+				hdev->children[port] = NULL;
+				usb_put_dev(udev);
+				hub_port_disable(hdev, port);
 				return;
 			}
 		}
  
 		/* check for devices running slower than they could */
-		if (dev->descriptor.bcdUSB >= 0x0200
-				&& dev->speed == USB_SPEED_FULL
+		if (udev->descriptor.bcdUSB >= 0x0200
+				&& udev->speed == USB_SPEED_FULL
 				&& highspeed_hubs != 0)
-			check_highspeed (hubstate, dev, port);
+			check_highspeed (hub, udev, port);
 
 		/* Run it through the hoops (find a driver, etc) */
-		status = usb_new_device(dev);
+		status = usb_new_device(udev);
 		if (status != 0) {
-			hub->children[port] = NULL;
+			hdev->children[port] = NULL;
 			continue;
 		}
-		up (&dev->serialize);
+		up (&udev->serialize);
 
-		status = hub_power_remaining(hubstate, hub);
+		status = hub_power_remaining(hub, hdev);
 		if (status)
-			dev_dbg(&hubstate->intf->dev,
+			dev_dbg(hub_dev,
 				"%dmA power budget left\n",
 				2 * status);
 
@@ -1389,15 +1408,16 @@
 	}
  
 done:
-	hub_port_disable(hub, port);
+	hub_port_disable(hdev, port);
 }
 
 static void hub_events(void)
 {
 	unsigned long flags;
 	struct list_head *tmp;
-	struct usb_device *dev;
+	struct usb_device *hdev;
 	struct usb_hub *hub;
+	struct device *hub_dev;
 	u16 hubstatus;
 	u16 hubchange;
 	u16 portstatus;
@@ -1420,7 +1440,8 @@
 		tmp = hub_event_list.next;
 
 		hub = list_entry(tmp, struct usb_hub, event_list);
-		dev = interface_to_usbdev(hub->intf);
+		hdev = interface_to_usbdev(hub->intf);
+		hub_dev = &hub->intf->dev;
 
 		list_del_init(tmp);
 
@@ -1430,14 +1451,14 @@
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
-			dev_dbg (&hub->intf->dev, "resetting for error %d\n",
+			dev_dbg (hub_dev, "resetting for error %d\n",
 				hub->error);
 
 			if (hub_reset(hub)) {
-				dev_dbg (&hub->intf->dev,
+				dev_dbg (hub_dev,
 					"can't reset; disconnecting\n");
 				up(&hub->khubd_sem);
-				hub_start_disconnect(dev);
+				hub_start_disconnect(hdev);
 				continue;
 			}
 
@@ -1446,7 +1467,7 @@
 		}
 
 		for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
-			ret = hub_port_status(dev, i, &portstatus, &portchange);
+			ret = hub_port_status(hdev, i, &portstatus, &portchange);
 			if (ret < 0) {
 				continue;
 			}
@@ -1454,10 +1475,10 @@
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
 				hub_port_connect_change(hub, i, portstatus, portchange);
 			} else if (portchange & USB_PORT_STAT_C_ENABLE) {
-				dev_dbg (hubdev (dev),
+				dev_dbg (hub_dev,
 					"port %d enable change, status %08x\n",
 					i + 1, portstatus);
-				clear_port_feature(dev,
+				clear_port_feature(hdev,
 					i + 1, USB_PORT_FEAT_C_ENABLE);
 
 				/*
@@ -1468,8 +1489,8 @@
 				 */
 				if (!(portstatus & USB_PORT_STAT_ENABLE)
 				    && (portstatus & USB_PORT_STAT_CONNECTION)
-				    && (dev->children[i])) {
-					dev_err (&hub->intf->dev,
+				    && (hdev->children[i])) {
+					dev_err (hub_dev,
 					    "port %i "
 					    "disabled by hub (EMI?), "
 					    "re-enabling...",
@@ -1480,43 +1501,43 @@
 			}
 
 			if (portchange & USB_PORT_STAT_C_SUSPEND) {
-				dev_dbg (&hub->intf->dev,
+				dev_dbg (hub_dev,
 					"suspend change on port %d\n",
 					i + 1);
-				clear_port_feature(dev,
+				clear_port_feature(hdev,
 					i + 1,  USB_PORT_FEAT_C_SUSPEND);
 			}
 			
 			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
-				dev_err (&hub->intf->dev,
+				dev_err (hub_dev,
 					"over-current change on port %d\n",
 					i + 1);
-				clear_port_feature(dev,
+				clear_port_feature(hdev,
 					i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
 				hub_power_on(hub);
 			}
 
 			if (portchange & USB_PORT_STAT_C_RESET) {
-				dev_dbg (&hub->intf->dev,
+				dev_dbg (hub_dev,
 					"reset change on port %d\n",
 					i + 1);
-				clear_port_feature(dev,
+				clear_port_feature(hdev,
 					i + 1, USB_PORT_FEAT_C_RESET);
 			}
 		} /* end for i */
 
 		/* deal with hub status changes */
 		if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
-			dev_err (&hub->intf->dev, "get_hub_status failed\n");
+			dev_err (hub_dev, "get_hub_status failed\n");
 		else {
 			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
-				dev_dbg (&hub->intf->dev, "power change\n");
-				clear_hub_feature(dev, C_HUB_LOCAL_POWER);
+				dev_dbg (hub_dev, "power change\n");
+				clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
-				dev_dbg (&hub->intf->dev, "overcurrent change\n");
+				dev_dbg (hub_dev, "overcurrent change\n");
 				msleep(500);	/* Cool down */
-				clear_hub_feature(dev, C_HUB_OVER_CURRENT);
+				clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
                         	hub_power_on(hub);
 			}
 		}
@@ -1526,7 +1547,7 @@
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 }
 
-static int hub_thread(void *__hub)
+static int hub_thread(void *__unused)
 {
 	/*
 	 * This thread doesn't need any user-level access,
@@ -1614,36 +1635,36 @@
 } /* usb_hub_cleanup() */
 
 
-static int config_descriptors_changed(struct usb_device *dev)
+static int config_descriptors_changed(struct usb_device *udev)
 {
 	unsigned			index;
 	unsigned			len = 0;
 	struct usb_config_descriptor	*buf;
 
-	for (index = 0; index < dev->descriptor.bNumConfigurations; index++) {
-		if (len < dev->config[index].desc.wTotalLength)
-			len = dev->config[index].desc.wTotalLength;
+	for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
+		if (len < udev->config[index].desc.wTotalLength)
+			len = udev->config[index].desc.wTotalLength;
 	}
 	buf = kmalloc (len, SLAB_KERNEL);
 	if (buf == 0) {
-		dev_err(&dev->dev, "no mem to re-read configs after reset\n");
+		dev_err(&udev->dev, "no mem to re-read configs after reset\n");
 		/* assume the worst */
 		return 1;
 	}
-	for (index = 0; index < dev->descriptor.bNumConfigurations; index++) {
+	for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
 		int length;
-		int old_length = dev->config[index].desc.wTotalLength;
+		int old_length = udev->config[index].desc.wTotalLength;
 
-		length = usb_get_descriptor(dev, USB_DT_CONFIG, index, buf,
+		length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf,
 				old_length);
 		if (length < old_length) {
-			dev_dbg(&dev->dev, "config index %d, error %d\n",
+			dev_dbg(&udev->dev, "config index %d, error %d\n",
 					index, length);
 			break;
 		}
-		if (memcmp (buf, dev->rawdescriptors[index], old_length)
+		if (memcmp (buf, udev->rawdescriptors[index], old_length)
 				!= 0) {
-			dev_dbg(&dev->dev, "config index %d changed (#%d)\n",
+			dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
 				index, buf->bConfigurationValue);
 /* FIXME enable this when we can re-enumerate after reset;
  * until then DFU-ish drivers need this and other workarounds
@@ -1652,7 +1673,7 @@
 		}
 	}
 	kfree(buf);
-	return index != dev->descriptor.bNumConfigurations;
+	return index != udev->descriptor.bNumConfigurations;
 }
 
 /*
@@ -1664,22 +1685,22 @@
  * already holds dev->serialize.  For example, it's safe to use
  * this from a driver probe() routine after downloading new firmware.
  */
-int __usb_reset_device(struct usb_device *dev)
+int __usb_reset_device(struct usb_device *udev)
 {
-	struct usb_device *parent = dev->parent;
-	struct usb_device_descriptor descriptor = dev->descriptor;
+	struct usb_device *parent = udev->parent;
+	struct usb_device_descriptor descriptor = udev->descriptor;
 	int i, ret, port = -1;
 
-	if (dev->maxchild) {
+	if (udev->maxchild) {
 		/* this requires hub- or hcd-specific logic;
 		 * see hub_reset() and OHCI hc_restart()
 		 */
-		dev_dbg(&dev->dev, "%s for hub!\n", __FUNCTION__);
+		dev_dbg(&udev->dev, "%s for hub!\n", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	for (i = 0; i < parent->maxchild; i++)
-		if (parent->children[i] == dev) {
+		if (parent->children[i] == udev) {
 			port = i;
 			break;
 		}
@@ -1687,45 +1708,45 @@
 	if (port < 0)
 		return -ENOENT;
 
-	ret = hub_port_init(parent, dev, port);
+	ret = hub_port_init(parent, udev, port);
 	if (ret < 0)
 		goto re_enumerate;
  
 	/* Device might have changed firmware (DFU or similar) */
-	if (memcmp(&dev->descriptor, &descriptor, sizeof descriptor)
-			|| config_descriptors_changed (dev)) {
-		dev_info(&dev->dev, "device firmware changed\n");
-		dev->descriptor = descriptor;	/* for disconnect() calls */
+	if (memcmp(&udev->descriptor, &descriptor, sizeof descriptor)
+			|| config_descriptors_changed (udev)) {
+		dev_info(&udev->dev, "device firmware changed\n");
+		udev->descriptor = descriptor;	/* for disconnect() calls */
 		goto re_enumerate;
   	}
   
-	if (!dev->actconfig)
+	if (!udev->actconfig)
 		return 0;
 
-	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			USB_REQ_SET_CONFIGURATION, 0,
-			dev->actconfig->desc.bConfigurationValue, 0,
+			udev->actconfig->desc.bConfigurationValue, 0,
 			NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
 	if (ret < 0) {
-		dev_err(&dev->dev,
+		dev_err(&udev->dev,
 			"can't restore configuration #%d (error=%d)\n",
-			dev->actconfig->desc.bConfigurationValue, ret);
+			udev->actconfig->desc.bConfigurationValue, ret);
 		goto re_enumerate;
   	}
-	dev->state = USB_STATE_CONFIGURED;
+	udev->state = USB_STATE_CONFIGURED;
 
-	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
-		struct usb_interface *intf = dev->actconfig->interface[i];
+	for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+		struct usb_interface *intf = udev->actconfig->interface[i];
 		struct usb_interface_descriptor *desc;
 
 		/* set_interface resets host side toggle and halt status even
 		 * for altsetting zero.  the interface may have no driver.
 		 */
 		desc = &intf->cur_altsetting->desc;
-		ret = usb_set_interface(dev, desc->bInterfaceNumber,
+		ret = usb_set_interface(udev, desc->bInterfaceNumber,
 			desc->bAlternateSetting);
 		if (ret < 0) {
-			dev_err(&dev->dev, "failed to restore interface %d "
+			dev_err(&udev->dev, "failed to restore interface %d "
 				"altsetting %d (error=%d)\n",
 				desc->bInterfaceNumber,
 				desc->bAlternateSetting,
@@ -1738,7 +1759,7 @@
  
 re_enumerate:
 	/* FIXME make some task re-enumerate; don't just mark unusable */
-	dev->state = USB_STATE_NOTATTACHED;
+	udev->state = USB_STATE_NOTATTACHED;
 	return -ENODEV;
 }
 EXPORT_SYMBOL(__usb_reset_device);
--- diff/drivers/usb/core/message.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/usb/core/message.c	2004-05-27 18:34:18.000000000 +0100
@@ -1252,7 +1252,7 @@
 					ret);
 				continue;
 			}
-			usb_create_driverfs_intf_files (intf);
+			usb_create_sysfs_intf_files (intf);
 		}
 	}
 
--- diff/drivers/usb/core/usb.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/usb/core/usb.c	2004-05-27 18:34:18.000000000 +0100
@@ -998,12 +998,10 @@
 	 */
 	usb_disable_device(dev, 0);
 
-	dev_dbg (&dev->dev, "unregistering device\n");
 	/* Free the device number and remove the /proc/bus/usb entry */
-	if (dev->devnum > 0) {
-		clear_bit(dev->devnum, dev->bus->devmap.devicemap);
-		usbfs_remove_device(dev);
-	}
+	dev_dbg (&dev->dev, "unregistering device\n");
+	usb_release_address(dev);
+	usbfs_remove_device(dev);
 	up(&dev->serialize);
 	device_unregister(&dev->dev);
 }
@@ -1038,24 +1036,23 @@
 	}
 }
 
-
-// hub-only!! ... and only exported for reset/reinit path.
-// otherwise used internally, for usb_new_device()
-int usb_set_address(struct usb_device *dev)
+/**
+ * usb_release_address - deallocate device address (usbcore-internal)
+ * @dev: newly removed device
+ *
+ * Removes and deallocates the address assigned to a device.
+ * Only hub drivers (but not virtual root hub drivers for host
+ * controllers) should ever call this.
+ */
+void usb_release_address(struct usb_device *dev)
 {
-	int retval;
-
-	if (dev->devnum == 0)
-		return -EINVAL;
-	if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
-		return -EINVAL;
-	retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
-		0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
-	if (retval == 0)
-		dev->state = USB_STATE_ADDRESS;
-	return retval;
+	if (dev->devnum > 0) {
+		clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+		dev->devnum = -1;
+	}
 }
 
+
 static inline void usb_show_string(struct usb_device *dev, char *id, int index)
 {
 	char *buf;
@@ -1069,6 +1066,37 @@
 	kfree(buf);
 }
 
+static int usb_choose_configuration(struct usb_device *dev)
+{
+	int c, i;
+
+	c = dev->config[0].desc.bConfigurationValue;
+	if (dev->descriptor.bNumConfigurations != 1) {
+		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+			struct usb_interface_descriptor	*desc;
+
+			/* heuristic:  Linux is more likely to have class
+			 * drivers, so avoid vendor-specific interfaces.
+			 */
+			desc = &dev->config[i].intf_cache[0]
+					->altsetting->desc;
+			if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
+				continue;
+			/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
+			if (desc->bInterfaceClass == USB_CLASS_COMM
+					&& desc->bInterfaceSubClass == 2
+					&& desc->bInterfaceProtocol == 0xff)
+				continue;
+			c = dev->config[i].desc.bConfigurationValue;
+			break;
+		}
+		dev_info(&dev->dev,
+			"configuration #%d chosen from %d choices\n",
+			c, dev->descriptor.bNumConfigurations);
+	}
+	return c;
+}
+
 /*
  * usb_new_device - perform initial device setup (usbcore-internal)
  * @dev: newly addressed device (in ADDRESS state)
@@ -1090,8 +1118,7 @@
 int usb_new_device(struct usb_device *dev)
 {
 	int err;
-	int i;
-	int config;
+	int c;
 
 	err = usb_get_configuration(dev);
 	if (err < 0) {
@@ -1119,41 +1146,16 @@
 		dev_err(&dev->dev, "can't device_add, error %d\n", err);
 		goto fail;
 	}
-	usb_create_driverfs_dev_files (dev);
+	usb_create_sysfs_dev_files (dev);
 
 	/* choose and set the configuration. that registers the interfaces
 	 * with the driver core, and lets usb device drivers bind to them.
 	 * NOTE:  should interact with hub power budgeting.
 	 */
-	config = dev->config[0].desc.bConfigurationValue;
-	if (dev->descriptor.bNumConfigurations != 1) {
-		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
-			struct usb_interface_descriptor	*desc;
-
-			/* heuristic:  Linux is more likely to have class
-			 * drivers, so avoid vendor-specific interfaces.
-			 */
-			desc = &dev->config[i].intf_cache[0]
-					->altsetting->desc;
-			if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
-				continue;
-			/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
-			if (desc->bInterfaceClass == USB_CLASS_COMM
-					&& desc->bInterfaceSubClass == 2
-					&& desc->bInterfaceProtocol == 0xff)
-				continue;
-			config = dev->config[i].desc.bConfigurationValue;
-			break;
-		}
-		dev_info(&dev->dev,
-			"configuration #%d chosen from %d choices\n",
-			config,
-			dev->descriptor.bNumConfigurations);
-	}
-	err = usb_set_configuration(dev, config);
+	c = usb_choose_configuration(dev);
+	err = usb_set_configuration(dev, c);
 	if (err) {
-		dev_err(&dev->dev, "can't set config #%d, error %d\n",
-			config, err);
+		dev_err(&dev->dev, "can't set config #%d, error %d\n", c, err);
 		device_del(&dev->dev);
 		goto fail;
 	}
@@ -1166,8 +1168,7 @@
 	return 0;
 fail:
 	dev->state = USB_STATE_NOTATTACHED;
-	clear_bit(dev->devnum, dev->bus->devmap.devicemap);
-	dev->devnum = -1;
+	usb_release_address(dev);
 	usb_put_dev(dev);
 	return err;
 }
--- diff/drivers/usb/core/usb.h	2004-05-19 22:12:17.000000000 +0100
+++ source/drivers/usb/core/usb.h	2004-05-27 18:34:18.000000000 +0100
@@ -1,7 +1,7 @@
 /* Functions local to drivers/usb/core/ */
 
-extern void usb_create_driverfs_dev_files (struct usb_device *dev);
-extern void usb_create_driverfs_intf_files (struct usb_interface *intf);
+extern void usb_create_sysfs_dev_files (struct usb_device *dev);
+extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
 extern int usb_probe_interface (struct device *dev);
 extern int usb_unbind_interface (struct device *dev);
 
--- diff/drivers/usb/gadget/Kconfig	2004-05-19 22:12:17.000000000 +0100
+++ source/drivers/usb/gadget/Kconfig	2004-05-27 18:34:18.000000000 +0100
@@ -95,6 +95,7 @@
 config USB_PXA2XX_SMALL
 	depends on USB_GADGET_PXA2XX
 	bool
+	default n if USB_ETH_RNDIS
 	default y if USB_ZERO
 	default y if USB_ETH
 	default y if USB_G_SERIAL
--- diff/drivers/usb/gadget/epautoconf.c	2004-05-19 22:12:17.000000000 +0100
+++ source/drivers/usb/gadget/epautoconf.c	2004-05-27 18:34:18.000000000 +0100
@@ -96,7 +96,8 @@
 				/* for now, avoid PXA "interrupt-in";
 				 * it's documented as never using DATA1.
 				 */
-				if (gadget_is_pxa (gadget))
+				if (gadget_is_pxa (gadget)
+						&& 'i' == tmp [1])
 					return 0;
 				break;
 			case USB_ENDPOINT_XFER_BULK:
--- diff/drivers/usb/gadget/pxa2xx_udc.c	2004-05-19 22:12:17.000000000 +0100
+++ source/drivers/usb/gadget/pxa2xx_udc.c	2004-05-27 18:34:18.000000000 +0100
@@ -51,6 +51,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
+#include <asm/mach-types.h>
 #include <asm/unaligned.h>
 #include <asm/hardware.h>
 
--- diff/drivers/usb/gadget/serial.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/usb/gadget/serial.c	2004-05-27 18:34:18.000000000 +0100
@@ -154,14 +154,9 @@
 
 #define GS_CLOSE_TIMEOUT		15
 
-/* debug macro */
+/* debug settings */
 #if G_SERIAL_DEBUG
 static int debug = G_SERIAL_DEBUG;
-#else
-static int debug = 0;
-#endif
-
-#if G_SERIAL_DEBUG
 
 #define gs_debug(format, arg...) \
 	do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
@@ -598,8 +593,10 @@
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 
+#if G_SERIAL_DEBUG
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
+#endif
 
 MODULE_PARM(read_q_size, "i");
 MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
--- diff/drivers/usb/host/uhci-hcd.c	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/usb/host/uhci-hcd.c	2004-05-27 18:34:18.000000000 +0100
@@ -95,6 +95,10 @@
 static int uhci_get_current_frame_number(struct uhci_hcd *uhci);
 static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
 static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
+static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs);
+static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
+static void uhci_free_pending_tds(struct uhci_hcd *uhci);
 
 static void hc_state_transitions(struct uhci_hcd *uhci);
 
@@ -373,6 +377,7 @@
 {
 	struct uhci_qh *pqh;
 	u32 newlink;
+	unsigned int age;
 
 	if (!qh)
 		return;
@@ -425,6 +430,12 @@
 	list_del_init(&qh->urbp->queue_list);
 	qh->urbp = NULL;
 
+	age = uhci_get_current_frame_number(uhci);
+	if (age != uhci->qh_remove_age) {
+		uhci_free_pending_qhs(uhci);
+		uhci->qh_remove_age = age;
+	}
+
 	/* Check to see if the remove list is empty. Set the IOC bit */
 	/* to force an interrupt so we can remove the QH */
 	if (list_empty(&uhci->qh_remove_list))
@@ -628,6 +639,7 @@
 {
 	struct list_head *head, *tmp;
 	struct urb_priv *urbp;
+	unsigned int age;
 
 	urbp = (struct urb_priv *)urb->hcpriv;
 	if (!urbp)
@@ -637,6 +649,12 @@
 		dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
 				"or uhci->remove_list!\n", urb);
 
+	age = uhci_get_current_frame_number(uhci);
+	if (age != uhci->td_remove_age) {
+		uhci_free_pending_tds(uhci);
+		uhci->td_remove_age = age;
+	}
+
 	/* Check to see if the remove list is empty. Set the IOC bit */
 	/* to force an interrupt so we can remove the TD's*/
 	if (list_empty(&uhci->td_remove_list))
@@ -1512,6 +1530,7 @@
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	unsigned long flags;
 	struct urb_priv *urbp;
+	unsigned int age;
 
 	spin_lock_irqsave(&uhci->schedule_lock, flags);
 	urbp = urb->hcpriv;
@@ -1521,6 +1540,12 @@
 
 	uhci_unlink_generic(uhci, urb);
 
+	age = uhci_get_current_frame_number(uhci);
+	if (age != uhci->urb_remove_age) {
+		uhci_remove_pending_urbps(uhci);
+		uhci->urb_remove_age = age;
+	}
+
 	/* If we're the first, set the next interrupt bit */
 	if (list_empty(&uhci->urb_remove_list))
 		uhci_set_next_interrupt(uhci);
@@ -1590,6 +1615,12 @@
 	INIT_LIST_HEAD(&list);
 
 	spin_lock_irqsave(&uhci->schedule_lock, flags);
+	if (!list_empty(&uhci->urb_remove_list) &&
+	    uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
+		uhci_remove_pending_urbps(uhci);
+		uhci_finish_completion(hcd, NULL);
+	}
+
 	head = &uhci->urb_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1728,6 +1759,7 @@
 	unsigned int io_addr = uhci->io_addr;
 	unsigned short status;
 	struct list_head *tmp, *head;
+	unsigned int age;
 
 	/*
 	 * Read the interrupt status, and write it back to clear the
@@ -1758,11 +1790,20 @@
 
 	spin_lock(&uhci->schedule_lock);
 
-	uhci_free_pending_qhs(uhci);
-	uhci_free_pending_tds(uhci);
-	uhci_remove_pending_urbps(uhci);
-
-	uhci_clear_next_interrupt(uhci);
+	age = uhci_get_current_frame_number(uhci);
+	if (age != uhci->qh_remove_age)
+		uhci_free_pending_qhs(uhci);
+	if (age != uhci->td_remove_age)
+		uhci_free_pending_tds(uhci);
+	if (age != uhci->urb_remove_age)
+		uhci_remove_pending_urbps(uhci);
+
+	if (list_empty(&uhci->urb_remove_list) &&
+	    list_empty(&uhci->td_remove_list) &&
+	    list_empty(&uhci->qh_remove_list))
+		uhci_clear_next_interrupt(uhci);
+	else
+		uhci_set_next_interrupt(uhci);
 
 	/* Walk the list of pending URB's to see which ones completed */
 	head = &uhci->urb_list;
--- diff/drivers/usb/host/uhci-hcd.h	2004-05-27 13:41:21.000000000 +0100
+++ source/drivers/usb/host/uhci-hcd.h	2004-05-27 18:34:18.000000000 +0100
@@ -357,12 +357,15 @@
 
 	/* List of QH's that are done, but waiting to be unlinked (race) */
 	struct list_head qh_remove_list;	/* P: uhci->schedule_lock */
+	unsigned int qh_remove_age;		/* Age in frames */
 
 	/* List of TD's that are done, but waiting to be freed (race) */
 	struct list_head td_remove_list;	/* P: uhci->schedule_lock */
+	unsigned int td_remove_age;		/* Age in frames */
 
 	/* List of asynchronously unlinked URB's */
 	struct list_head urb_remove_list;	/* P: uhci->schedule_lock */
+	unsigned int urb_remove_age;		/* Age in frames */
 
 	/* List of URB's awaiting completion callback */
 	struct list_head complete_list;		/* P: uhci->schedule_lock */
--- diff/drivers/usb/input/hiddev.c	2004-05-19 22:12:18.000000000 +0100
+++ source/drivers/usb/input/hiddev.c	2004-05-27 18:34:18.000000000 +0100
@@ -232,7 +232,7 @@
 static struct usb_class_driver hiddev_class;
 static void hiddev_cleanup(struct hiddev *hiddev)
 {
-	hiddev_table[hiddev->hid->minor] = NULL;
+	hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
 	usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
 	kfree(hiddev);
 }
@@ -612,7 +612,7 @@
 		uref = &uref_multi->uref;
 		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
 			if (copy_from_user(uref_multi, (void *) arg, 
-					   sizeof(uref_multi)))
+					   sizeof(*uref_multi)))
 				goto fault;
 		} else {
 			if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
--- diff/drivers/usb/input/powermate.c	2004-05-19 22:12:18.000000000 +0100
+++ source/drivers/usb/input/powermate.c	2004-05-27 18:34:18.000000000 +0100
@@ -33,6 +33,7 @@
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include <linux/usb.h>
 
 #define POWERMATE_VENDOR	0x077d	/* Griffin Technology, Inc. */
@@ -67,7 +68,7 @@
 	dma_addr_t configcr_dma;
 	struct usb_device *udev;
 	struct input_dev input;
-	struct semaphore lock;
+	spinlock_t lock;
 	int static_brightness;
 	int pulse_speed;
 	int pulse_table;
@@ -116,7 +117,7 @@
 		     __FUNCTION__, retval);
 }
 
-/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */
+/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
 static void powermate_sync_state(struct powermate_device *pm)
 {
 	if (pm->requires_update == 0) 
@@ -194,19 +195,22 @@
 static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
 {
 	struct powermate_device *pm = urb->context;
+	unsigned long flags;
 
 	if (urb->status)
 		printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
 	
-	down(&pm->lock);
+	spin_lock_irqsave(&pm->lock, flags);
 	powermate_sync_state(pm);
-	up(&pm->lock);
+	spin_unlock_irqrestore(&pm->lock, flags);
 }
 
 /* Set the LED up as described and begin the sync with the hardware if required */
 static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, 
 				int pulse_table, int pulse_asleep, int pulse_awake)
 {
+	unsigned long flags;
+
 	if (pulse_speed < 0)
 		pulse_speed = 0;
 	if (pulse_table < 0)
@@ -219,7 +223,8 @@
 	pulse_asleep = !!pulse_asleep;
 	pulse_awake = !!pulse_awake;
 
-	down(&pm->lock);
+
+	spin_lock_irqsave(&pm->lock, flags);
 
 	/* mark state updates which are required */
 	if (static_brightness != pm->static_brightness){
@@ -242,7 +247,7 @@
 
 	powermate_sync_state(pm);
    
-	up(&pm->lock);
+	spin_unlock_irqrestore(&pm->lock, flags);
 }
 
 /* Callback from the Input layer when an event arrives from userspace to configure the LED */
@@ -344,7 +349,7 @@
 		return -ENOMEM;
 	}
 
-	init_MUTEX(&pm->lock);
+	pm->lock = SPIN_LOCK_UNLOCKED;
 	init_input_dev(&pm->input);
 
 	/* get a handle to the interrupt data pipe */
@@ -411,7 +416,6 @@
 
 	usb_set_intfdata(intf, NULL);
 	if (pm) {
-		down(&pm->lock);
 		pm->requires_update = 0;
 		usb_unlink_urb(pm->irq);
 		input_unregister_device(&pm->input);
--- diff/drivers/usb/misc/emi26.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/usb/misc/emi26.c	2004-05-27 18:34:18.000000000 +0100
@@ -194,7 +194,7 @@
 
 	/* return 1 to fail the driver inialization
 	 * and give real driver change to load */
-	return 1;
+	err = 1;
 
 wraperr:
 	kfree(buf);
--- diff/drivers/usb/misc/emi62.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/usb/misc/emi62.c	2004-05-27 18:34:18.000000000 +0100
@@ -229,6 +229,8 @@
 		goto wraperr;
 	}
 
+	kfree(buf);
+
 	/* return 1 to fail the driver inialization
 	 * and give real driver change to load */
 	return 1;
--- diff/drivers/usb/net/kaweth.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/usb/net/kaweth.c	2004-05-27 18:34:18.000000000 +0100
@@ -1240,20 +1240,21 @@
         init_waitqueue_head(&awd.wqh);
         awd.done = 0;
 
-        set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&awd.wqh, &wait);
         urb->context = &awd;
-        status = usb_submit_urb(urb, GFP_ATOMIC);
+        status = usb_submit_urb(urb, GFP_NOIO);
         if (status) {
                 // something went wrong
                 usb_free_urb(urb);
-                set_current_state(TASK_RUNNING);
                 remove_wait_queue(&awd.wqh, &wait);
                 return status;
         }
 
-	while (timeout && !awd.done)
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	while (timeout && !awd.done) {
 		timeout = schedule_timeout(timeout);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+	}
 
         set_current_state(TASK_RUNNING);
         remove_wait_queue(&awd.wqh, &wait);
--- diff/drivers/usb/net/pegasus.h	2004-05-19 22:12:19.000000000 +0100
+++ source/drivers/usb/net/pegasus.h	2004-05-27 18:34:18.000000000 +0100
@@ -136,6 +136,7 @@
 #define	VENDOR_LANEED		0x056e
 #define	VENDOR_LINKSYS		0x066b
 #define	VENDOR_MELCO		0x0411
+#define	VENDOR_MICROSOFT	0x045e
 #define	VENDOR_MOBILITY		0x1342
 #define	VENDOR_NETGEAR		0x0846
 #define	VENDOR_OCT		0x0b39
@@ -265,6 +266,8 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109,
--- diff/drivers/usb/serial/Kconfig	2004-05-19 22:12:19.000000000 +0100
+++ source/drivers/usb/serial/Kconfig	2004-05-27 18:34:18.000000000 +0100
@@ -314,8 +314,8 @@
 	  module will be called kl5kusb105.
 
 config USB_SERIAL_KOBIL_SCT
-        tristate "USB KOBIL chipcard reader (EXPERIMENTAL)"
-        depends on USB_SERIAL && EXPERIMENTAL
+        tristate "USB KOBIL chipcard reader"
+        depends on USB_SERIAL
         ---help---
           Say Y here if you want to use one of the following KOBIL USB chipcard
           readers:
--- diff/drivers/usb/serial/kobil_sct.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/usb/serial/kobil_sct.c	2004-05-27 18:34:18.000000000 +0100
@@ -21,6 +21,9 @@
  * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
  * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
  * 
+ * (21/05/2004) tw
+ *      Fix bug with P'n'P readers
+ *
  * (28/05/2003) tw
  *      Add support for KAAN SIM
  *
@@ -59,7 +62,7 @@
 #include "usb-serial.h"
 
 /* Version Information */
-#define DRIVER_VERSION "28/05/2003"
+#define DRIVER_VERSION "21/05/2004"
 #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
 #define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
 
@@ -339,6 +342,12 @@
 			);
 		dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
 	}
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
+	    priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
+		// start reading (Adapter B 'cause PNP string)
+		result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC  ); 
+		dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+	}
 
 	kfree(transfer_buffer);
 	return 0;
@@ -456,6 +465,11 @@
 	if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || 
 	     ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
 		
+		// stop reading (except TWIN and KAAN SIM)
+		if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
+			usb_unlink_urb( port->interrupt_in_urb );
+		}
+
 		todo = priv->filled - priv->cur_pos;
 
 		while(todo > 0) {
@@ -463,25 +477,23 @@
 			length = (todo < 8) ? todo : 8;
 			// copy data to transfer buffer
 			memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length );
-			
-			usb_fill_bulk_urb( port->write_urb,
-					   port->serial->dev,
-					   usb_sndbulkpipe( port->serial->dev, priv->write_int_endpoint_address),
-					   port->write_urb->transfer_buffer,
-					   length,
-					   kobil_write_callback,
-					   port
+			usb_fill_int_urb( port->write_urb,
+					  port->serial->dev,
+					  usb_sndintpipe(port->serial->dev, priv->write_int_endpoint_address),
+					  port->write_urb->transfer_buffer,
+					  length,
+					  kobil_write_callback,
+					  port,
+					  8
 				);
 
 			priv->cur_pos = priv->cur_pos + length;
-			result = usb_submit_urb( port->write_urb, GFP_ATOMIC );
+			result = usb_submit_urb( port->write_urb, GFP_NOIO );
 			dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
 			todo = priv->filled - priv->cur_pos;
 
 			if (todo > 0) {
-				//mdelay(16);
-				set_current_state(TASK_UNINTERRUPTIBLE);
-				schedule_timeout(24 * HZ / 1000);
+				msleep(24);
 			}
 
 		} // end while
@@ -492,9 +504,14 @@
 		// someone sets the dev to 0 if the close method has been called
 		port->interrupt_in_urb->dev = port->serial->dev;
 		
-		// start reading
-		result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC ); 
-		dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+		// start reading (except TWIN and KAAN SIM)
+		if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
+			// someone sets the dev to 0 if the close method has been called
+			port->interrupt_in_urb->dev = port->serial->dev;
+			
+			result = usb_submit_urb( port->interrupt_in_urb, GFP_NOIO ); 
+			dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+		}
 	}
 	return count;
 }
--- diff/drivers/usb/serial/visor.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/usb/serial/visor.c	2004-05-27 18:34:18.000000000 +0100
@@ -680,7 +680,7 @@
 	char *string;
 	int retval = 0;
 	int i;
-	int num_ports;
+	int num_ports = 0;
 
 	dbg("%s", __FUNCTION__);
 
@@ -702,41 +702,50 @@
 			__FUNCTION__, retval);
 		goto exit;
 	}
-		
-	connection_info = (struct visor_connection_info *)transfer_buffer;
 
-	le16_to_cpus(&connection_info->num_ports);
-	num_ports = connection_info->num_ports;
-	/* handle devices that report invalid stuff here */
-	if (num_ports > 2)
-		num_ports = 2;
-	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
-		connection_info->num_ports);
+	if (retval == sizeof(*connection_info)) {
+	        connection_info = (struct visor_connection_info *)transfer_buffer;
 
-	for (i = 0; i < num_ports; ++i) {
-		switch (connection_info->connections[i].port_function_id) {
-			case VISOR_FUNCTION_GENERIC:
-				string = "Generic";
-				break;
-			case VISOR_FUNCTION_DEBUGGER:
-				string = "Debugger";
-				break;
-			case VISOR_FUNCTION_HOTSYNC:
-				string = "HotSync";
-				break;
-			case VISOR_FUNCTION_CONSOLE:
-				string = "Console";
-				break;
-			case VISOR_FUNCTION_REMOTE_FILE_SYS:
-				string = "Remote File System";
-				break;
-			default:
-				string = "unknown";
-				break;	
+		le16_to_cpus(&connection_info->num_ports);
+		num_ports = connection_info->num_ports;
+
+		for (i = 0; i < num_ports; ++i) {
+			switch (connection_info->connections[i].port_function_id) {
+				case VISOR_FUNCTION_GENERIC:
+					string = "Generic";
+					break;
+				case VISOR_FUNCTION_DEBUGGER:
+					string = "Debugger";
+					break;
+				case VISOR_FUNCTION_HOTSYNC:
+					string = "HotSync";
+					break;
+				case VISOR_FUNCTION_CONSOLE:
+					string = "Console";
+					break;
+				case VISOR_FUNCTION_REMOTE_FILE_SYS:
+					string = "Remote File System";
+					break;
+				default:
+					string = "unknown";
+					break;
+			}
+			dev_info(dev, "%s: port %d, is for %s use\n",
+				serial->type->name,
+				connection_info->connections[i].port, string);
 		}
-		dev_info(dev, "%s: port %d, is for %s use\n", serial->type->name,
-			 connection_info->connections[i].port, string);
 	}
+	/*
+	* Handle devices that report invalid stuff here.
+	*/
+	if (num_ports == 0 || num_ports > 2) {
+		dev_warn (dev, "%s: No valid connect info available\n",
+			serial->type->name);
+		num_ports = 2;
+	}
+  
+	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
+		num_ports);
 
 	/*
 	 * save off our num_ports info so that we can use it in the
@@ -868,8 +877,7 @@
  
 static int treo_attach (struct usb_serial *serial)
 {
-	struct usb_serial_port *port;
-	int i;
+	struct usb_serial_port *swap_port;
 
 	/* Only do this endpoint hack for the Handspring devices with
 	 * interrupt in endpoints, which for now are the Treo devices. */
@@ -879,31 +887,28 @@
 
 	dbg("%s", __FUNCTION__);
 
-	/* Ok, this is pretty ugly, but these devices want to use the
-	 * interrupt endpoint as paired up with a bulk endpoint for a
-	 * "virtual serial port".  So let's force the endpoints to be
-	 * where we want them to be. */
-	for (i = serial->num_bulk_in; i < serial->num_ports; ++i) {
-		port = serial->port[i];
-		port->read_urb = serial->port[0]->read_urb;
-		port->bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress;
-		port->bulk_in_buffer = serial->port[0]->bulk_in_buffer;
-	}
-
-	for (i = serial->num_bulk_out; i < serial->num_ports; ++i) {
-		port = serial->port[i];
-		port->write_urb = serial->port[0]->write_urb;
-		port->bulk_out_size = serial->port[0]->bulk_out_size;
-		port->bulk_out_endpointAddress = serial->port[0]->bulk_out_endpointAddress;
-		port->bulk_out_buffer = serial->port[0]->bulk_out_buffer;
-	}
-
-	for (i = serial->num_interrupt_in; i < serial->num_ports; ++i) {
-		port = serial->port[i];
-		port->interrupt_in_urb = serial->port[0]->interrupt_in_urb;
-		port->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
-		port->interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
-	}
+	/*
+	* It appears that Treos want to use the 1st interrupt endpoint to
+	* communicate with the 2nd bulk out endpoint, so let's swap the 1st
+	* and 2nd bulk in and interrupt endpoints.  Note that swapping the
+	* bulk out endpoints would break lots of apps that want to communicate
+	* on the second port.
+	*/
+#define COPY_PORT(dest, src)						\
+	dest->read_urb = src->read_urb;					\
+	dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;	\
+	dest->bulk_in_buffer = src->bulk_in_buffer;			\
+	dest->interrupt_in_urb = src->interrupt_in_urb;			\
+	dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress;	\
+	dest->interrupt_in_buffer = src->interrupt_in_buffer;
+
+	swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL);
+	if (!swap_port)
+		return -ENOMEM;
+	COPY_PORT(swap_port, serial->port[0]);
+	COPY_PORT(serial->port[0], serial->port[1]);
+	COPY_PORT(serial->port[1], swap_port);
+	kfree(swap_port);
 
 	return 0;
 }
--- diff/drivers/usb/storage/transport.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/usb/storage/transport.c	2004-05-27 18:34:18.000000000 +0100
@@ -1112,8 +1112,7 @@
 
 	/* long wait for reset, so unlock to allow disconnects */
 	up(&us->dev_semaphore);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ*6);
+	msleep(6000);
 	down(&us->dev_semaphore);
 	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
 		US_DEBUGP("Reset interrupted by disconnect\n");
--- diff/drivers/usb/storage/unusual_devs.h	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/usb/storage/unusual_devs.h	2004-05-27 18:34:18.000000000 +0100
@@ -366,6 +366,12 @@
 		"USB Hard Disk",
 		US_SC_RBC, US_PR_CB, NULL, 0 ), 
 
+/* Submitted by Jol Bourquard <numlock@freesurf.ch> */
+UNUSUAL_DEV(  0x05ab, 0x0060, 0x1104, 0x1110,
+		"In-System",
+		"PyroGate External CD-ROM Enclosure (FCD-523)",
+		US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x05ab, 0x0031, 0x0100, 0x0110,
 		"In-System",
--- diff/drivers/video/aty/atyfb_base.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/video/aty/atyfb_base.c	2004-05-27 18:34:18.000000000 +0100
@@ -1938,6 +1938,19 @@
 			if (i < 0)
 				continue;
 
+			rp = &pdev->resource[0];
+			if (rp->flags & IORESOURCE_IO)
+				rp = &pdev->resource[1];
+			addr = rp->start;
+			if (!addr)
+				continue;
+
+			res_start = rp->start;
+			res_size = rp->end - rp->start + 1;
+			if (!request_mem_region
+			    (res_start, res_size, "atyfb"))
+				continue;
+
 			info =
 			    kmalloc(sizeof(struct fb_info), GFP_ATOMIC);
 			if (!info) {
@@ -1960,19 +1973,6 @@
 			info->fix = atyfb_fix;
 			info->par = default_par;
 
-			rp = &pdev->resource[0];
-			if (rp->flags & IORESOURCE_IO)
-				rp = &pdev->resource[1];
-			addr = rp->start;
-			if (!addr)
-				continue;
-
-			res_start = rp->start;
-			res_size = rp->end - rp->start + 1;
-			if (!request_mem_region
-			    (res_start, res_size, "atyfb"))
-				continue;
-
 #ifdef __sparc__
 			/*
 			 * Map memory-mapped registers.
@@ -2000,6 +2000,7 @@
 			if (!default_par->mmap_map) {
 				printk
 				    ("atyfb_init: can't alloc mmap_map\n");
+				kfree(default_par);
 				kfree(info);
 				release_mem_region(res_start, res_size);
 				return -ENXIO;
@@ -2217,6 +2218,9 @@
 			    ioremap(info->fix.mmio_start, 0x1000);
 
 			if (!default_par->ati_regbase) {
+#ifdef __sparc__
+				kfree(default_par->mmap_map);
+#endif
 				kfree(default_par);
 				kfree(info);
 				release_mem_region(res_start, res_size);
@@ -2247,6 +2251,10 @@
 			    (char *) ioremap(addr, 0x800000);
 
 			if (!info->screen_base) {
+#ifdef __sparc__
+				kfree(default_par->mmap_map);
+#endif
+				kfree(default_par);
 				kfree(info);
 				release_mem_region(res_start, res_size);
 				return -ENXIO;
@@ -2258,6 +2266,7 @@
 				if (default_par->mmap_map)
 					kfree(default_par->mmap_map);
 #endif
+				kfree(default_par);
 				kfree(info);
 				release_mem_region(res_start, res_size);
 				return -ENXIO;
@@ -2326,6 +2335,7 @@
 		memset(default_par, 0, sizeof(struct atyfb_par));
 
 		info->fix = atyfb_fix;
+		info->par = default_par;
 
 		/*
 		 *  Map the video memory (physical address given) to somewhere in the
@@ -2357,6 +2367,7 @@
 		}
 
 		if (!aty_init(info, "ISA bus")) {
+			kfree(default_par);
 			kfree(info);
 			/* This is insufficient! kernel_map has added two large chunks!! */
 			return -ENXIO;
--- diff/drivers/video/aty/radeon_accel.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/video/aty/radeon_accel.c	2004-05-27 18:34:18.000000000 +0100
@@ -13,7 +13,10 @@
 		rinfo->dp_gui_master_cntl  /* contains, like GMC_DST_32BPP */
                 | GMC_BRUSH_SOLID_COLOR
                 | ROP3_P);
-	OUTREG(DP_BRUSH_FRGD_CLR, region->color);
+        if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP)
+		OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]);
+	else
+		OUTREG(DP_BRUSH_FRGD_CLR, region->color);
 	OUTREG(DP_WRITE_MSK, 0xffffffff);
 	OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
 
--- diff/drivers/video/aty/radeon_pm.c	2004-05-19 22:12:22.000000000 +0100
+++ source/drivers/video/aty/radeon_pm.c	2004-05-27 18:34:18.000000000 +0100
@@ -867,7 +867,7 @@
 	}
 
 	/* Blank display and LCD */
-	radeonfb_blank(VESA_POWERDOWN+1, info);
+	radeonfb_blank(VESA_POWERDOWN, info);
 
 	/* Sleep */
 	rinfo->asleep = 1;
--- diff/drivers/video/console/sticore.c	2004-05-19 22:12:22.000000000 +0100
+++ source/drivers/video/console/sticore.c	2004-05-27 18:34:18.000000000 +0100
@@ -22,7 +22,6 @@
 #include <linux/pci.h>
 #include <linux/font.h>
 
-#include <asm/pgalloc.h>
 #include <asm/hardware.h>
 #include <asm/parisc-device.h>
 #include <asm/cacheflush.h>
--- diff/drivers/video/matrox/matroxfb_DAC1064.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/matrox/matroxfb_DAC1064.c	2004-05-27 18:34:18.000000000 +0100
@@ -660,7 +660,7 @@
 	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
 
 	ACCESS_FBINFO(outputs[0]).output = &m1064;
-	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
 	ACCESS_FBINFO(outputs[0]).data = MINFO;
 	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
@@ -859,7 +859,7 @@
 	{
 		ACCESS_FBINFO(outputs[0]).output = &m1064;
 	}
-	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
 	ACCESS_FBINFO(outputs[0]).data = MINFO;
 	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
--- diff/drivers/video/matrox/matroxfb_Ti3026.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/matrox/matroxfb_Ti3026.c	2004-05-27 18:34:18.000000000 +0100
@@ -692,7 +692,7 @@
 
 	ACCESS_FBINFO(outputs[0]).data = MINFO;
 	ACCESS_FBINFO(outputs[0]).output = &ti3026_output;
-	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
 	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
 	if (ACCESS_FBINFO(devflags.noinit))
--- diff/drivers/video/matrox/matroxfb_base.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/matrox/matroxfb_base.c	2004-05-27 18:34:18.000000000 +0100
@@ -1272,6 +1272,7 @@
 static int dfp;				/* "matrox:dfp */
 static int dfp_type = -1;		/* "matrox:dfp:xxx */
 static int memtype = -1;		/* "matrox:memtype:xxx" */
+static char outputs[8];			/* "matrox:outputs:xxx" */
 
 #ifndef MODULE
 static char videomode[64];		/* "matrox:mode:xxxxx" or "matrox:xxxxx" */
@@ -1537,6 +1538,39 @@
 
 static int hotplug = 0;
 
+static void setDefaultOutputs(WPMINFO2) {
+	unsigned int i;
+	const char* ptr;
+
+	ACCESS_FBINFO(outputs[0]).default_src = MATROXFB_SRC_CRTC1;
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		ACCESS_FBINFO(outputs[1]).default_src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[2]).default_src = MATROXFB_SRC_CRTC1;
+	} else if (dfp) {
+		ACCESS_FBINFO(outputs[2]).default_src = MATROXFB_SRC_CRTC1;
+	}
+	ptr = outputs;
+	for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+		char c = *ptr++;
+
+		if (c == 0) {
+			break;
+		}
+		if (c == '0') {
+			ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_NONE;
+		} else if (c == '1') {
+			ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_CRTC1;
+		} else if (c == '2' && ACCESS_FBINFO(devflags.crtc2)) {
+			ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_CRTC2;
+		} else {
+			printk(KERN_ERR "matroxfb: Unknown outputs setting\n");
+			break;
+		}
+	}
+	/* Nullify this option for subsequent adapters */
+	outputs[0] = 0;
+}
+
 static int initMatrox2(WPMINFO struct board* b){
 	unsigned long ctrlptr_phys = 0;
 	unsigned long video_base_phys = 0;
@@ -1577,20 +1611,18 @@
 	ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0;
 	ACCESS_FBINFO(devflags.maven_capable) = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
 	ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0;
+	ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
+	ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0;
+	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
+	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
+	setDefaultOutputs(PMINFO2);
 	if (b->flags & DEVF_PANELLINK_CAPABLE) {
 		ACCESS_FBINFO(outputs[2]).data = MINFO;
 		ACCESS_FBINFO(outputs[2]).output = &panellink_output;
-		if (dfp)
-			ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
-		else
-			ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[2]).src = ACCESS_FBINFO(outputs[2]).default_src;
 		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 		ACCESS_FBINFO(devflags.panellink) = 1;
 	}
-	ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
-	ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0;
-	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
-	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
 
 	if (ACCESS_FBINFO(capable.cross4MB) < 0)
 		ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
@@ -1813,6 +1845,13 @@
 							to yres_virtual * xres_virtual < 2^32 */
 	}
 	matroxfb_init_fix(PMINFO2);
+	/* Normalize values (namely yres_virtual) */
+	matroxfb_check_var(&vesafb_defined, &ACCESS_FBINFO(fbcon));
+	/* And put it into "current" var. Do NOT program hardware yet, or we'll not take over
+	 * vgacon correctly. fbcon_startup will call fb_set_par for us, WITHOUT check_var,
+	 * and unfortunately it will do it BEFORE vgacon contents is saved, so it won't work
+	 * anyway. But we at least tried... */
+	ACCESS_FBINFO(fbcon.var) = vesafb_defined;
 	err = -EINVAL;
 
 	printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
@@ -1834,6 +1873,9 @@
 		 * until someone tells me what is proper thing to do */
 		printk(KERN_INFO "fb%d: initializing hardware\n",
 			ACCESS_FBINFO(fbcon.node));
+		/* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
+		 * already before, so register_framebuffer works correctly. */
+		vesafb_defined.activate |= FB_ACTIVATE_FORCE;
 		fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
 	}
 	return 0;
@@ -2288,6 +2330,8 @@
 			mem = simple_strtoul(this_opt+4, NULL, 0);
 		else if (!strncmp(this_opt, "mode:", 5))
 			strlcpy(videomode, this_opt+5, sizeof(videomode));
+		else if (!strncmp(this_opt, "outputs:", 8))
+			strlcpy(outputs, this_opt+8, sizeof(outputs));
 		else if (!strncmp(this_opt, "dfp:", 4)) {
 			dfp_type = simple_strtoul(this_opt+4, NULL, 0);
 			dfp = 1;
@@ -2463,6 +2507,8 @@
 MODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)");
 MODULE_PARM(dfp_type, "i");
 MODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)");
+MODULE_PARM(outputs, "c8");
+MODULE_PARM_DESC(outputs, "Specifies which CRTC is mapped to which output (string of up to three letters, consisting of 0 (disabled), 1 (CRTC1), 2 (CRTC2)) (default=111 for Gx50, 101 for G200/G400 with DFP, and 100 for all other devices)");
 #ifdef CONFIG_PPC_PMAC
 MODULE_PARM(vmode, "i");
 MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
--- diff/drivers/video/matrox/matroxfb_base.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/matrox/matroxfb_base.h	2004-05-27 18:34:18.000000000 +0100
@@ -479,6 +479,7 @@
 	struct matrox_altout*	output;
 	void*			data;
 	unsigned int		mode;
+	unsigned int		default_src;
 			      } outputs[MATROXFB_MAX_OUTPUTS];
 
 #define MATROXFB_MAX_FB_DRIVERS		5
--- diff/drivers/video/matrox/matroxfb_crtc2.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/matrox/matroxfb_crtc2.c	2004-05-27 18:34:18.000000000 +0100
@@ -628,15 +628,6 @@
 	m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase);
 	m2info->mmio.len = ACCESS_FBINFO(mmio.len);
 
-	/*
-	 *  If we have unused output, connect CRTC2 to it...
-	 */
-	if (ACCESS_FBINFO(outputs[1]).output &&
-	    ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_NONE &&
-	    ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_NONE) {
-		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2;
-	}
-
 	matroxfb_dh_init_fix(m2info);
 	if (register_framebuffer(&m2info->fbcon)) {
 		return -ENXIO;
--- diff/drivers/video/matrox/matroxfb_g450.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/matrox/matroxfb_g450.c	2004-05-27 18:34:18.000000000 +0100
@@ -591,11 +591,11 @@
 	if (ACCESS_FBINFO(devflags.g450dac)) {
 		down_write(&ACCESS_FBINFO(altout.lock));
 		tvo_fill_defaults(PMINFO2);
-		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
 		ACCESS_FBINFO(outputs[1]).data = MINFO;
 		ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
 		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
-		ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[2]).src = ACCESS_FBINFO(outputs[2]).default_src;
 		ACCESS_FBINFO(outputs[2]).data = MINFO;
 		ACCESS_FBINFO(outputs[2]).output = &matroxfb_g450_dvi;
 		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
--- diff/drivers/video/matrox/matroxfb_maven.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/matrox/matroxfb_maven.c	2004-05-27 18:34:18.000000000 +0100
@@ -1188,7 +1188,7 @@
 	md->client = clnt;
 	down_write(&ACCESS_FBINFO(altout.lock));
 	ACCESS_FBINFO(outputs[1]).output = &maven_altout;
-	ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+	ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
 	ACCESS_FBINFO(outputs[1]).data = md;
 	ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 	up_write(&ACCESS_FBINFO(altout.lock));
@@ -1249,6 +1249,7 @@
 		err = -ENOMEM;
 		goto ERROR0;
 	}
+	memset(new_client, 0, sizeof(*new_client) + sizeof(*data));
 	data = (struct maven_data*)(new_client + 1);
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
--- diff/drivers/video/pxafb.c	2004-05-27 13:41:22.000000000 +0100
+++ source/drivers/video/pxafb.c	2004-05-27 18:34:18.000000000 +0100
@@ -153,7 +153,7 @@
 		 * 12 or 16-bit True Colour.  We encode the RGB value
 		 * according to the RGB bitfield information.
 		 */
-		if (regno <= 16) {
+		if (regno < 16) {
 			u32 *pal = fbi->fb.pseudo_palette;
 
 			val  = chan_to_field(red, &fbi->fb.var.red);
@@ -448,7 +448,7 @@
 {
 	struct pxafb_lcd_reg new_regs;
 	u_long flags;
-	u_int pcd = get_pcd(var->pixclock);
+	u_int lines_per_panel, pcd = get_pcd(var->pixclock);
 
 	DPRINTK("Configuring PXA LCD\n");
 
@@ -509,8 +509,16 @@
 		LCCR1_BegLnDel(var->left_margin) +
 		LCCR1_EndLnDel(var->right_margin);
 
+	/*
+	 * If we have a dual scan LCD, we need to halve
+	 * the YRES parameter.
+	 */
+	lines_per_panel = var->yres;
+	if (fbi->lccr0 & LCCR0_SDS)
+		lines_per_panel /= 2;
+
 	new_regs.lccr2 =
-		LCCR2_DisHght(var->yres) +
+		LCCR2_DisHght(lines_per_panel) +
 		LCCR2_VrtSnchWdth(var->vsync_len) +
 		LCCR2_BegFrmDel(var->upper_margin) +
 		LCCR2_EndFrmDel(var->lower_margin);
@@ -540,9 +548,7 @@
 	fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
 	fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
 
-	#define BYTES_PER_PANEL ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual ? \
-                                (var->xres * var->yres * var->bits_per_pixel / 8 / 2) : \
-                                (var->xres * var->yres * var->bits_per_pixel / 8))
+#define BYTES_PER_PANEL (lines_per_panel * fbi->fb.fix.line_length)
 
 	/* populate descriptors */
 	fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
@@ -733,8 +739,7 @@
 
 	LCSR = 0xffffffff;	/* Clear LCD Status Register */
 	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
-	//TODO?enable_irq(IRQ_LCD);  /* Enable LCD IRQ */
-	LCCR0 &= ~LCCR0_ENB;	/* Disable LCD Controller */
+	LCCR0 |= LCCR0_DIS;	/* Disable LCD Controller */
 
 	schedule_timeout(20 * HZ / 1000);
 	remove_wait_queue(&fbi->ctrlr_wait, &wait);
@@ -1137,25 +1142,25 @@
 				}
                 } else if (!strncmp(this_opt, "pixclock:", 9)) {
                         inf->pixclock = simple_strtoul(this_opt+9, NULL, 0);
-			dev_info(dev, "override pixclock: %uld\n", inf->pixclock);
+			dev_info(dev, "override pixclock: %u\n", inf->pixclock);
                 } else if (!strncmp(this_opt, "left:", 5)) {
                         inf->left_margin = simple_strtoul(this_opt+5, NULL, 0);
-			dev_info(dev, "override left: %d\n", inf->left_margin);
+			dev_info(dev, "override left: %u\n", inf->left_margin);
                 } else if (!strncmp(this_opt, "right:", 6)) {
                         inf->right_margin = simple_strtoul(this_opt+6, NULL, 0);
-			dev_info(dev, "override right: %d\n", inf->right_margin);
+			dev_info(dev, "override right: %u\n", inf->right_margin);
                 } else if (!strncmp(this_opt, "upper:", 6)) {
                         inf->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
-			dev_info(dev, "override upper: %d\n", inf->upper_margin);
+			dev_info(dev, "override upper: %u\n", inf->upper_margin);
                 } else if (!strncmp(this_opt, "lower:", 6)) {
                         inf->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
-			dev_info(dev, "override lower: %d\n", inf->lower_margin);
+			dev_info(dev, "override lower: %u\n", inf->lower_margin);
                 } else if (!strncmp(this_opt, "hsynclen:", 9)) {
                         inf->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
-			dev_info(dev, "override hsynclen: %d\n", inf->hsync_len);
+			dev_info(dev, "override hsynclen: %u\n", inf->hsync_len);
                 } else if (!strncmp(this_opt, "vsynclen:", 9)) {
                         inf->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
-			dev_info(dev, "override vsynclen: %d\n", inf->vsync_len);
+			dev_info(dev, "override vsynclen: %u\n", inf->vsync_len);
                 } else if (!strncmp(this_opt, "hsync:", 6)) {
                         if ( simple_strtoul(this_opt+6, NULL, 0) == 0 ) {
 				dev_info(dev, "override hsync: Active Low\n");
--- diff/drivers/video/tgafb.c	2004-05-19 22:12:21.000000000 +0100
+++ source/drivers/video/tgafb.c	2004-05-27 18:34:18.000000000 +0100
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/fb.h>
 #include <linux/pci.h>
+#include <linux/selection.h>
 #include <asm/io.h>
 #include <video/tgafb.h>
 #include <linux/selection.h>
--- diff/fs/Kconfig	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/Kconfig	2004-05-27 18:34:18.000000000 +0100
@@ -327,6 +327,7 @@
 
 config XFS_FS
 	tristate "XFS filesystem support"
+	select QSORT
 	help
 	  XFS is a high performance journaling filesystem which originated
 	  on the SGI IRIX platform.  It is completely multi-threaded, can
--- diff/fs/affs/symlink.c	2004-05-19 22:12:24.000000000 +0100
+++ source/fs/affs/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -78,7 +78,8 @@
 };
 
 struct inode_operations affs_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.setattr	= affs_notify_change,
 };
--- diff/fs/autofs/symlink.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/autofs/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -12,19 +12,14 @@
 
 #include "autofs_i.h"
 
-static int autofs_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
-	return vfs_readlink(dentry, buffer, buflen, s);
-}
-
 static int autofs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
-	return vfs_follow_link(nd, s);
+	nd_set_link(nd, s);
+	return 0;
 }
 
 struct inode_operations autofs_symlink_inode_operations = {
-	.readlink	= autofs_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= autofs_follow_link
 };
--- diff/fs/autofs4/symlink.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/autofs4/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -12,21 +12,14 @@
 
 #include "autofs_i.h"
 
-static int autofs4_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-	return vfs_readlink(dentry, buffer, buflen, ino->u.symlink);
-}
-
 static int autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-	return vfs_follow_link(nd, ino->u.symlink);
+	nd_set_link(nd, (char *)ino->u.symlink);
+	return 0;
 }
 
 struct inode_operations autofs4_symlink_inode_operations = {
-	.readlink	= autofs4_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= autofs4_follow_link
 };
--- diff/fs/bad_inode.c	2004-05-19 22:12:24.000000000 +0100
+++ source/fs/bad_inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -21,7 +21,8 @@
  */
 static int bad_follow_link(struct dentry *dent, struct nameidata *nd)
 {
-	return vfs_follow_link(nd, ERR_PTR(-EIO));
+	nd_set_link(nd, ERR_PTR(-EIO));
+	return 0;
 }
 
 static int return_EIO(void)
--- diff/fs/befs/linuxvfs.c	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/befs/linuxvfs.c	2004-05-27 18:34:18.000000000 +0100
@@ -40,8 +40,8 @@
 static void befs_destroy_inode(struct inode *inode);
 static int befs_init_inodecache(void);
 static void befs_destroy_inodecache(void);
-static int befs_readlink(struct dentry *, char __user *, int);
-static int befs_follow_link(struct dentry *, struct nameidata *nd);
+static int befs_follow_link(struct dentry *, struct nameidata *);
+static void befs_put_link(struct dentry *, struct nameidata *);
 static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
 static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
@@ -85,8 +85,9 @@
 };
 
 static struct inode_operations befs_symlink_inode_operations = {
-	.readlink	= befs_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= befs_follow_link,
+	.put_link	= befs_put_link,
 };
 
 /* 
@@ -462,71 +463,40 @@
 static int
 befs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct super_block *sb = dentry->d_sb;
 	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
 	char *link;
-	int res;
 
 	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
+		struct super_block *sb = dentry->d_sb;
 		befs_data_stream *data = &befs_ino->i_data.ds;
-		befs_off_t linklen = data->size;
+		befs_off_t len = data->size;
 
 		befs_debug(sb, "Follow long symlink");
 
-		link = kmalloc(linklen, GFP_NOFS);
-		if (link == NULL)
-			return -ENOMEM;
-
-		if (befs_read_lsymlink(sb, data, link, linklen) != linklen) {
+		link = kmalloc(len, GFP_NOFS);
+		if (!link) {
+			link = ERR_PTR(-ENOMEM);
+		} else if (befs_read_lsymlink(sb, data, link, len) != len) {
 			kfree(link);
 			befs_error(sb, "Failed to read entire long symlink");
-			return -EIO;
+			link = ERR_PTR(-EIO);
 		}
-
-		res = vfs_follow_link(nd, link);
-
-		kfree(link);
 	} else {
 		link = befs_ino->i_data.symlink;
-		res = vfs_follow_link(nd, link);
 	}
 
-	return res;
+	nd_set_link(nd, link);
+	return 0;
 }
 
-static int
-befs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+static void befs_put_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct super_block *sb = dentry->d_sb;
 	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
-	char *link;
-	int res;
-
 	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
-		befs_data_stream *data = &befs_ino->i_data.ds;
-		befs_off_t linklen = data->size;
-
-		befs_debug(sb, "Read long symlink");
-
-		link = kmalloc(linklen, GFP_NOFS);
-		if (link == NULL)
-			return -ENOMEM;
-
-		if (befs_read_lsymlink(sb, data, link, linklen) != linklen) {
-			kfree(link);
-			befs_error(sb, "Failed to read entire long symlink");
-			return -EIO;
-		}
-
-		res = vfs_readlink(dentry, buffer, buflen, link);
-
-		kfree(link);
-	} else {
-		link = befs_ino->i_data.symlink;
-		res = vfs_readlink(dentry, buffer, buflen, link);
+		char *p = nd_get_link(nd);
+		if (!IS_ERR(p))
+			kfree(p);
 	}
-
-	return res;
 }
 
 /*
@@ -571,7 +541,7 @@
 		}
 
 		/* convert from Unicode to nls */
-		unilen = nls->uni2char(uni, &result[o], 1);
+		unilen = nls->uni2char(uni, &result[o], in_len - o);
 		if (unilen < 0) {
 			goto conv_err;
 		}
@@ -584,7 +554,7 @@
 	return o;
 
       conv_err:
-	befs_error(sb, "Name using charecter set %s contains a charecter that "
+	befs_error(sb, "Name using character set %s contains a character that "
 		   "cannot be converted to unicode.", nls->charset);
 	befs_debug(sb, "<--- utf2nls()");
 	kfree(result);
--- diff/fs/binfmt_aout.c	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/binfmt_aout.c	2004-05-27 18:34:18.000000000 +0100
@@ -27,7 +27,6 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 
 static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
--- diff/fs/binfmt_elf.c	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/binfmt_elf.c	2004-05-27 18:34:18.000000000 +0100
@@ -40,7 +40,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/param.h>
-#include <asm/pgalloc.h>
 
 #include <linux/elf.h>
 
--- diff/fs/binfmt_flat.c	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/binfmt_flat.c	2004-05-27 18:34:18.000000000 +0100
@@ -40,7 +40,6 @@
 #include <asm/byteorder.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
 
--- diff/fs/binfmt_misc.c	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/binfmt_misc.c	2004-05-27 18:34:18.000000000 +0100
@@ -39,6 +39,8 @@
 
 enum {Enabled, Magic};
 #define MISC_FMT_PRESERVE_ARGV0 (1<<31)
+#define MISC_FMT_OPEN_BINARY (1<<30)
+#define MISC_FMT_CREDENTIALS (1<<29)
 
 typedef struct {
 	struct list_head list;
@@ -102,10 +104,13 @@
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
 	Node *fmt;
-	struct file * file;
+	struct file * interp_file = NULL;
 	char iname[BINPRM_BUF_SIZE];
 	char *iname_addr = iname;
 	int retval;
+	int fd_binary = -1;
+	char fd_str[12];
+	struct files_struct *files = NULL;
 
 	retval = -ENOEXEC;
 	if (!enabled)
@@ -120,33 +125,102 @@
 	if (!fmt)
 		goto _ret;
 
-	allow_write_access(bprm->file);
-	fput(bprm->file);
-	bprm->file = NULL;
-
-	/* Build args for interpreter */
 	if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
 		remove_arg_zero(bprm);
 	}
-	retval = copy_strings_kernel(1, &bprm->interp, bprm);
-	if (retval < 0) goto _ret; 
-	bprm->argc++;
-	retval = copy_strings_kernel(1, &iname_addr, bprm);
-	if (retval < 0) goto _ret; 
-	bprm->argc++;
-	bprm->interp = iname;	/* for binfmt_script */
 
-	file = open_exec(iname);
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		goto _ret;
-	bprm->file = file;
+	if (fmt->flags & MISC_FMT_OPEN_BINARY) {
+		char *fdsp = fd_str;
+
+		files = current->files;
+		retval = unshare_files();
+		if (retval < 0)
+			goto _ret;
+		if (files == current->files) {
+			put_files_struct(files);
+			files = NULL;
+		}
+		/* if the binary should be opened on behalf of the
+		 * interpreter than keep it open and assign descriptor
+		 * to it */
+ 		fd_binary = get_unused_fd();
+ 		if (fd_binary < 0) {
+ 			retval = fd_binary;
+ 			goto _unshare;
+ 		}
+ 		fd_install(fd_binary, bprm->file);
+
+		/* if the binary is not readable than enforce mm->dumpable=0
+		   regardless of the interpreter's permissions */
+		if (permission(bprm->file->f_dentry->d_inode, MAY_READ, NULL))
+			bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+
+		allow_write_access(bprm->file);
+		bprm->file = NULL;
+
+		/* make argv[1] be the file descriptor of the binary */
+ 		snprintf(fd_str, sizeof(fd_str), "%d", fd_binary);
+ 		retval = copy_strings_kernel(1, &fdsp, bprm);
+		if (retval < 0)
+			goto _error;
+		bprm->argc++;
+
+ 	} else {
+ 		allow_write_access(bprm->file);
+ 		fput(bprm->file);
+ 		bprm->file = NULL;
+		/* make argv[1] be the path to the binary */
+ 		retval = copy_strings_kernel (1, &bprm->interp, bprm);
+		if (retval < 0)
+			goto _error;
+		bprm->argc++;
+ 	}
+	retval = copy_strings_kernel (1, &iname_addr, bprm);
+	if (retval < 0)
+		goto _error;
+	bprm->argc ++;
+	bprm->interp = iname;	/* for binfmt_script */
 
-	retval = prepare_binprm(bprm);
-	if (retval >= 0)
-		retval = search_binary_handler(bprm, regs);
+	interp_file = open_exec (iname);
+	retval = PTR_ERR (interp_file);
+	if (IS_ERR (interp_file))
+		goto _error;
+
+	bprm->file = interp_file;
+	if (fmt->flags & MISC_FMT_CREDENTIALS) {
+		/*
+		 * No need to call prepare_binprm(), it's already been
+		 * done.  bprm->buf is stale, update from interp_file.
+		 */
+		memset(bprm->buf, 0, BINPRM_BUF_SIZE);
+		retval = kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
+	} else
+		retval = prepare_binprm (bprm);
+
+	if (retval < 0)
+		goto _error;
+
+	retval = search_binary_handler (bprm, regs);
+	if (retval < 0)
+		goto _error;
+
+	if (files) {
+		steal_locks(files);
+		put_files_struct(files);
+		files = NULL;
+	}
 _ret:
 	return retval;
+_error:
+	if (fd_binary > 0)
+		sys_close(fd_binary);
+	bprm->interp_flags = 0;
+_unshare:
+	if (files) {
+		put_files_struct(current->files);
+		current->files = files;
+	}
+	goto _ret;
 }
 
 /* Command parsers */
@@ -191,9 +265,39 @@
 	return p - from;
 }
 
+static inline char * check_special_flags (char * sfs, Node * e)
+{
+	char * p = sfs;
+	int cont = 1;
+
+	/* special flags */
+	while (cont) {
+		switch (*p) {
+			case 'P':
+				p++;
+				e->flags |= MISC_FMT_PRESERVE_ARGV0;
+				break;
+			case 'O':
+				p++;
+				e->flags |= MISC_FMT_OPEN_BINARY;
+				break;
+			case 'C':
+				p++;
+				/* this flags also implies the
+				   open-binary flag */
+				e->flags |= (MISC_FMT_CREDENTIALS |
+						MISC_FMT_OPEN_BINARY);
+				break;
+			default:
+				cont = 0;
+		}
+	}
+
+	return p;
+}
 /*
  * This registers a new binary format, it recognises the syntax
- * ':name:type:offset:magic:mask:interpreter:'
+ * ':name:type:offset:magic:mask:interpreter:flags'
  * where the ':' is the IFS, that can be chosen with the first char
  */
 static Node *create_entry(const char *buffer, size_t count)
@@ -293,10 +397,8 @@
 	if (!e->interpreter[0])
 		goto Einval;
 
-	if (*p == 'P') {
-		p++;
-		e->flags |= MISC_FMT_PRESERVE_ARGV0;
-	}
+
+	p = check_special_flags (p, e);
 
 	if (*p == '\n')
 		p++;
@@ -346,6 +448,7 @@
 {
 	char *dp;
 	char *status = "disabled";
+	const char * flags = "flags: ";
 
 	if (test_bit(Enabled, &e->flags))
 		status = "enabled";
@@ -357,6 +460,22 @@
 
 	sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
 	dp = page + strlen(page);
+
+	/* print the special flags */
+	sprintf (dp, "%s", flags);
+	dp += strlen (flags);
+	if (e->flags & MISC_FMT_PRESERVE_ARGV0) {
+		*dp ++ = 'P';
+	}
+	if (e->flags & MISC_FMT_OPEN_BINARY) {
+		*dp ++ = 'O';
+	}
+	if (e->flags & MISC_FMT_CREDENTIALS) {
+		*dp ++ = 'C';
+	}
+	*dp ++ = '\n';
+
+
 	if (!test_bit(Magic, &e->flags)) {
 		sprintf(dp, "extension .%s\n", e->magic);
 	} else {
--- diff/fs/buffer.c	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/buffer.c	2004-05-27 18:34:18.000000000 +0100
@@ -947,7 +947,7 @@
 	spin_unlock(&mapping->private_lock);
 
 	if (!TestSetPageDirty(page)) {
-		spin_lock_irq(&mapping->tree_lock);
+		read_lock_irq(&mapping->tree_lock);
 		if (page->mapping) {	/* Race with truncate? */
 			if (!mapping->backing_dev_info->memory_backed)
 				inc_page_state(nr_dirty);
@@ -955,7 +955,7 @@
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
 		}
-		spin_unlock_irq(&mapping->tree_lock);
+		read_unlock_irq(&mapping->tree_lock);
 		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
 	}
 	
@@ -2753,21 +2753,31 @@
 	if (bio->bi_size)
 		return 1;
 
+	if (err == -EOPNOTSUPP)
+		set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
+
 	bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags));
 	bio_put(bio);
 	return 0;
 }
 
-void submit_bh(int rw, struct buffer_head * bh)
+int submit_bh(int rw, struct buffer_head * bh)
 {
 	struct bio *bio;
+	int ret = 0;
 
 	BUG_ON(!buffer_locked(bh));
 	BUG_ON(!buffer_mapped(bh));
 	BUG_ON(!bh->b_end_io);
 
-	/* Only clear out a write error when rewriting */
-	if (test_set_buffer_req(bh) && rw == WRITE)
+	if (buffer_ordered(bh) && (rw == WRITE))
+		rw = WRITE_BARRIER;
+
+	/*
+	 * Only clear out a write error when rewriting, should this
+	 * include WRITE_SYNC as well?
+	 */
+	if (test_set_buffer_req(bh) && (rw == WRITE || rw == WRITE_BARRIER))
 		clear_buffer_write_io_error(bh);
 
 	/*
@@ -2789,7 +2799,14 @@
 	bio->bi_end_io = end_bio_bh_io_sync;
 	bio->bi_private = bh;
 
+	bio_get(bio);
 	submit_bio(rw, bio);
+
+	if (bio_flagged(bio, BIO_EOPNOTSUPP))
+		ret = -EOPNOTSUPP;
+
+	bio_put(bio);
+	return ret;
 }
 
 /**
@@ -2848,20 +2865,26 @@
 
 /*
  * For a data-integrity writeout, we need to wait upon any in-progress I/O
- * and then start new I/O and then wait upon it.
+ * and then start new I/O and then wait upon it.  The caller must have a ref on
+ * the buffer_head.
  */
-void sync_dirty_buffer(struct buffer_head *bh)
+int sync_dirty_buffer(struct buffer_head *bh)
 {
+	int ret = 0;
+
 	WARN_ON(atomic_read(&bh->b_count) < 1);
 	lock_buffer(bh);
 	if (test_clear_buffer_dirty(bh)) {
 		get_bh(bh);
 		bh->b_end_io = end_buffer_write_sync;
-		submit_bh(WRITE, bh);
+		ret = submit_bh(WRITE, bh);
 		wait_on_buffer(bh);
+		if (!ret && !buffer_uptodate(bh))
+			ret = -EIO;
 	} else {
 		unlock_buffer(bh);
 	}
+	return ret;
 }
 
 /*
--- diff/fs/cifs/CHANGES	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/cifs/CHANGES	2004-05-27 18:34:18.000000000 +0100
@@ -1,3 +1,9 @@
+Version 1.16
+------------
+Fix incorrect file size in file handle based setattr on big endian hardware.
+Fix oops in build_path_from_dentry when out of memory.  Add checks for invalid
+and closing file structs in writepage/partialpagewrite
+
 Version 1.15
 ------------
 Change to mempools for alloc smb request buffers and multiplex structs
--- diff/fs/cifs/cifsfs.h	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/cifs/cifsfs.h	2004-05-27 18:34:18.000000000 +0100
@@ -93,5 +93,5 @@
 			 size_t, int);
 extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
-#define CIFS_VERSION   "1.15"
+#define CIFS_VERSION   "1.16"
 #endif				/* _CIFSFS_H */
--- diff/fs/cifs/cifspdu.h	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/cifs/cifspdu.h	2004-05-27 18:34:18.000000000 +0100
@@ -1687,6 +1687,83 @@
 	void (*free) (struct data_blob * data_blob);
 };
 
+#ifdef CIFS_POSIX
+/* 
+	For better POSIX semantics from Linux client, (even better
+	than the existing CIFS Unix Extensions) we need updated PDUs for:
+	
+	1) PosixCreateX - to set and return the mode, inode#, device info and
+	perhaps add a CreateDevice - to create Pipes and other special .inodes
+	Also note POSIX open flags
+	2) Close - to return the last write time to do cache across close more safely
+	3) PosixQFSInfo - to return statfs info
+	4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes)
+	5) Mkdir - set mode
+	
+	And under consideration: 
+	6) FindClose2 (return nanosecond timestamp ??)
+	7) Use nanosecond timestamps throughout all time fields if 
+	   corresponding attribute flag is set
+	8) sendfile - handle based copy
+	9) Direct i/o
+	10) "POSIX ACL" support
+	11) Misc fcntls?
+	
+	what about fixing 64 bit alignment
+	
+	There are also various legacy SMB/CIFS requests used as is
+	
+	From existing Lanman and NTLM dialects:
+	--------------------------------------
+	NEGOTIATE
+	SESSION_SETUP_ANDX (BB which?)
+	TREE_CONNECT_ANDX (BB which wct?)
+	TREE_DISCONNECT (BB add volume timestamp on response)
+	LOGOFF_ANDX
+	DELETE (note delete open file behavior)
+	DELETE_DIRECTORY
+	READ_AND_X
+	WRITE_AND_X
+	LOCKING_AND_X (note posix lock semantics)
+	RENAME (note rename across dirs and open file rename posix behaviors)
+	NT_RENAME (for hardlinks) Is this good enough for all features?
+	FIND_CLOSE2
+	TRANSACTION2 (18 cases)
+		SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2
+		(BB verify that never need to set allocation size)
+		SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?)
+	
+	COPY (note support for copy across directories) - FUTURE, OPTIONAL
+	setting/getting OS/2 EAs - FUTURE (BB can this handle
+	        setting Linux xattrs perfectly)         - OPTIONAL
+    dnotify                                         - FUTURE, OPTIONAL
+    quota                                           - FUTURE, OPTIONAL
+			
+	Note that various requests implemented for NT interop such as 
+		NT_TRANSACT (IOCTL) QueryReparseInfo
+	are unneeded to servers compliant with the CIFS POSIX extensions
+	
+	From CIFS Unix Extensions:
+	-------------------------
+	T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
+	T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
+	T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
+	T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields
+					Actually need QUERY_FILE_UNIX_INFO since has inode num
+					BB what about a) blksize/blkbits/blocks
+								  b) i_version
+								  c) i_rdev
+								  d) notify mask?
+								  e) generation
+								  f) size_seqcount
+	T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
+	TRANS2_GET_DFS_REFERRAL				  - OPTIONAL but recommended
+	T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
+	
+	
+ */
+#endif 
+
 #pragma pack()			/* resume default structure packing */
 
 #endif				/* _CIFSPDU_H */
--- diff/fs/cifs/cifssmb.c	2004-05-27 13:41:22.000000000 +0100
+++ source/fs/cifs/cifssmb.c	2004-05-27 18:34:18.000000000 +0100
@@ -37,13 +37,24 @@
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
 
+#ifdef CIFS_POSIX
 static struct {
 	int index;
 	char *name;
 } protocols[] = {
 	{CIFS_PROT, "\2NT LM 0.12"}, 
+	{CIFS_PROT, "\2POSIX 2"},
 	{BAD_PROT, "\2"}
 };
+#else
+static struct {
+	int index;
+	char *name;
+} protocols[] = {
+	{CIFS_PROT, "\2NT LM 0.12"}, 
+	{BAD_PROT, "\2"}
+};
+#endif
 
 
 /* Mark as invalid, all open files on tree connections since they
@@ -728,7 +739,7 @@
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
 	if (rc) {
-		cERROR(1, ("Send error in write = %d", rc));
+		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
 	} else
 		*nbytes = le16_to_cpu(pSMBr->Count);
@@ -792,7 +803,7 @@
 			 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
 
 	if (rc) {
-		cERROR(1, ("Send error in Lock = %d", rc));
+		cFYI(1, ("Send error in Lock = %d", rc));
 	}
 	if (pSMB)
 		cifs_buf_release(pSMB);
@@ -987,60 +998,59 @@
 
 int
 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
-              const __u16 target_tid, const char *toName, const int flags,
-              const struct nls_table *nls_codepage)
+            const __u16 target_tid, const char *toName, const int flags,
+            const struct nls_table *nls_codepage)
 {
-        int rc = 0;
-        COPY_REQ *pSMB = NULL;
-        COPY_RSP *pSMBr = NULL;
-        int bytes_returned;
-        int name_len, name_len2;
+	int rc = 0;
+	COPY_REQ *pSMB = NULL;
+	COPY_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len, name_len2;
 
-        cFYI(1, ("In CIFSSMBCopy"));
+	cFYI(1, ("In CIFSSMBCopy"));
 copyRetry:
-        rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
-        if (rc)
-                return rc;
+	rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
+			(void **) &pSMBr);
+	if (rc)
+		return rc;
 
-        pSMB->BufferFormat = 0x04;
+	pSMB->BufferFormat = 0x04;
 	pSMB->Tid2 = target_tid;
 
 	if(flags & COPY_TREE)
 		pSMB->Flags |= COPY_TREE;
 	pSMB->Flags = cpu_to_le16(pSMB->Flags);
 
-        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-                name_len =
-                    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
-                                  /* find define for this maxpathcomponent */
-                                  , nls_codepage);
-                name_len++;     /* trailing null */
-                name_len *= 2;
-                pSMB->OldFileName[name_len] = 0x04;     /* pad */
-        /* protocol requires ASCII signature byte on Unicode string */
-                pSMB->OldFileName[name_len + 1] = 0x00;
-                name_len2 =
-                    cifs_strtoUCS((wchar_t *) & pSMB->
-                                  OldFileName[name_len + 2], toName, 530,
-                                  nls_codepage);
-                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
-                name_len2 *= 2; /* convert to bytes */
-        } else {                /* BB improve the check for buffer overruns BB */
-                name_len = strnlen(fromName, 530);
-                name_len++;     /* trailing null */
-                strncpy(pSMB->OldFileName, fromName, name_len);
-                name_len2 = strnlen(toName, 530);
-                name_len2++;    /* trailing null */
-                pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
-                strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
-                name_len2++;    /* trailing null */
-                name_len2++;    /* signature byte */
-        }
-
-        pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;
-        pSMB->hdr.smb_buf_length += pSMB->ByteCount;
-        pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, 
+				fromName, 
+				530 /* find define for this maxpathcomponent */,
+				nls_codepage);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+		pSMB->OldFileName[name_len] = 0x04;     /* pad */
+		/* protocol requires ASCII signature byte on Unicode string */
+		pSMB->OldFileName[name_len + 1] = 0x00;
+		name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
+				OldFileName[name_len + 2], toName, 530,
+				nls_codepage);
+		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
+		name_len2 *= 2; /* convert to bytes */
+	} else {                /* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fromName, 530);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->OldFileName, fromName, name_len);
+		name_len2 = strnlen(toName, 530);
+		name_len2++;    /* trailing null */
+		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
+		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		name_len2++;    /* trailing null */
+		name_len2++;    /* signature byte */
+	}
+
+	pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -2581,7 +2591,7 @@
 		(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
 			pSMB->DataOffset);
 	pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */
-	parm_data->FileSize = size;
+	parm_data->FileSize = cpu_to_le64(size);
 	pSMB->Fid = fid;
 	if(SetAllocation) {
 		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
--- diff/fs/cifs/dir.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/cifs/dir.c	2004-05-27 18:34:18.000000000 +0100
@@ -38,7 +38,7 @@
 	do {
 		direntry->d_time = jiffies;
 		direntry = direntry->d_parent;
-	} while (!IS_ROOT(direntry));	/* BB for DFS case should stop at the root of share which could be lower than root of this mount due to implicit dfs connections */
+	} while (!IS_ROOT(direntry));	
 }
 
 /* Note: caller must free return buffer */
@@ -49,14 +49,26 @@
 	int namelen = 0;
 	char *full_path;
 
+	if(direntry == NULL)
+		return NULL;  /* not much we can do if dentry is freed and
+		we need to reopen the file after it was closed implicitly
+		when the server crashed */
+
+cifs_bp_rename_retry:
 	for (temp = direntry; !IS_ROOT(temp);) {
 		namelen += (1 + temp->d_name.len);
 		temp = temp->d_parent;
+		if(temp == NULL) {
+			cERROR(1,("corrupt dentry"));
+			return NULL;
+		}
 	}
-	namelen += 1;		/* allow for trailing null */
-	full_path = kmalloc(namelen, GFP_KERNEL);
-	namelen--;
+
+	full_path = kmalloc(namelen+1, GFP_KERNEL);
+	if(full_path == NULL)
+		return full_path;
 	full_path[namelen] = 0;	/* trailing null */
+
 	for (temp = direntry; !IS_ROOT(temp);) {
 		namelen -= 1 + temp->d_name.len;
 		if (namelen < 0) {
@@ -68,11 +80,23 @@
 			cFYI(0, (" name: %s ", full_path + namelen));
 		}
 		temp = temp->d_parent;
+		if(temp == NULL) {
+			cERROR(1,("corrupt dentry"));
+			kfree(full_path);
+			return NULL;
+		}
 	}
-	if (namelen != 0)
+	if (namelen != 0) {
 		cERROR(1,
 		       ("We did not end path lookup where we expected namelen is %d",
 			namelen));
+		/* presumably this is only possible if we were racing with a rename 
+		of one of the parent directories  (we can not lock the dentries
+		above us to prevent this, but retrying should be harmless) */
+		kfree(full_path);
+		namelen = 0;
+		goto cifs_bp_rename_retry;
+	}
 
 	return full_path;
 }
@@ -142,10 +166,12 @@
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 
-	if(nd) { 
-		cFYI(1,("In create for inode %p dentry->inode %p nd flags = 0x%x for %s",inode, direntry->d_inode, nd->flags,full_path));
-
+	if(nd) {
 		if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
 			desiredAccess = GENERIC_READ;
 		else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY)
@@ -173,6 +199,12 @@
 		oplock = REQ_OPLOCK;
 
 	buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+	if(buf == NULL) {
+		kfree(full_path);
+		FreeXid(xid);
+		return -ENOMEM;
+	}
+
 	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
 			 desiredAccess, CREATE_NOT_DIR,
 			 &fileHandle, &oplock, buf, cifs_sb->local_nls);
@@ -273,8 +305,10 @@
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(direntry);
-
-	if (pTcon->ses->capabilities & CAP_UNIX) {
+	if(full_path == NULL)
+		rc = -ENOMEM;
+	
+	if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
 		rc = CIFSSMBUnixSetPerms(xid, pTcon,
 			full_path, mode, current->euid, current->egid,
 			device_number, cifs_sb->local_nls);
@@ -298,7 +332,8 @@
 struct dentry *
 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct nameidata *nd)
 {
-	int rc, xid;
+	int xid;
+	int rc = 0; /* to get around spurious gcc warning, set to zero here */
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	struct inode *newInode = NULL;
@@ -321,6 +356,11 @@
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	if (direntry->d_inode != NULL) {
 		cFYI(1, (" non-NULL inode in lookup"));
 	} else {
@@ -347,10 +387,10 @@
 		rc = 0;
 		d_add(direntry, NULL);
 	} else {
-		cERROR(1,
-		       ("Error 0x%x or (%d decimal) on cifs_get_inode_info in lookup",
-			rc, rc));
-		/* BB special case check for Access Denied - watch security exposure of returning dir info implicitly via different rc if file exists or not but no access BB */
+		cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc));
+		/* BB special case check for Access Denied - watch security 
+		exposure of returning dir info implicitly via different rc 
+		if file exists or not but no access BB */
 	}
 
 	if (full_path)
--- diff/fs/cifs/fcntl.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/cifs/fcntl.c	2004-05-27 18:34:18.000000000 +0100
@@ -40,8 +40,13 @@
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
 	full_path = build_path_from_dentry(file->f_dentry);
-	cFYI(1,("cifs dir notify on file %s",full_path));
-	/* CIFSSMBNotify */
+	if(full_path == NULL) {
+		rc = -ENOMEM;
+	} else {
+		cFYI(1,("cifs dir notify on file %s",full_path));
+		/* CIFSSMBNotify(xid, pTcon, full_path, cifs_sb->local_nls);*/
+	}
+	
 	FreeXid(xid);
 	return rc;
 }
--- diff/fs/cifs/file.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/cifs/file.c	2004-05-27 18:34:18.000000000 +0100
@@ -81,6 +81,10 @@
 	}
 
 	full_path = build_path_from_dentry(file->f_dentry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 
 	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
@@ -150,8 +154,6 @@
 		cFYI(1, ("cifs_open returned 0x%x ", rc));
 		cFYI(1, ("oplock: %d ", oplock));	
 	} else {
-		if(file->private_data)
-			kfree(file->private_data);
 		file->private_data =
 			kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
 		if (file->private_data) {
@@ -281,11 +283,21 @@
 		return 0;
 	}
 
-
+	if(file->f_dentry == NULL) {
+		up(&pCifsFile->fh_sem);
+		cFYI(1,("failed file reopen, no valid name if dentry freed"));
+		FreeXid(xid);
+		return -EBADF;
+	}
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(file->f_dentry);
+	if(full_path == NULL) {
+		up(&pCifsFile->fh_sem);
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 
 	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
@@ -546,6 +558,9 @@
 	int xid, long_op;
 	struct cifsFileInfo * open_file;
 
+	if(file->f_dentry == NULL)
+		return -EBADF;
+
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -634,26 +649,22 @@
 	int bytes_written = 0;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
-	struct inode *inode = page->mapping->host;
+	struct inode *inode;
 	struct cifsInodeInfo *cifsInode;
 	struct cifsFileInfo *open_file = NULL;
 	struct list_head *tmp;
 	struct list_head *tmp1;
 
-	cifs_sb = CIFS_SB(inode->i_sb);
-	pTcon = cifs_sb->tcon;
-
-	/* figure out which file struct to use 
-	if (file->private_data == NULL) {
-		return -EBADF;
-	}     
-	 */
 	if (!mapping) {
 		return -EFAULT;
 	} else if(!mapping->host) {
 		return -EFAULT;
 	}
 
+	inode = page->mapping->host;
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
 	offset += (loff_t)from;
 	write_data = kmap(page);
 	write_data += from;
@@ -678,6 +689,8 @@
 	read_lock(&GlobalSMBSeslock); 
 	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
 		open_file = list_entry(tmp,struct cifsFileInfo, flist);
+		if(open_file->closePend)
+			continue;
 		/* We check if file is open for writing first */
 		if((open_file->pfile) && 
 		   ((open_file->pfile->f_flags & O_RDWR) || 
@@ -691,7 +704,15 @@
 			if ((bytes_written > 0) && (offset)) {
 				rc = 0;
 			} else if(bytes_written < 0) {
-				rc = bytes_written;
+				if(rc == -EBADF) {
+				/* have seen a case in which
+				kernel seemed to have closed/freed a file
+				even with writes active so we might as well
+				see if there are other file structs to try
+				for the same inode before giving up */
+					continue;
+				} else
+					rc = bytes_written;
 			}
 			break;  /* now that we found a valid file handle
 				and tried to write to it we are done, no
--- diff/fs/cifs/inode.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/cifs/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -346,7 +346,10 @@
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(direntry);
-
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 	rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
 
 	if (!rc) {
@@ -428,6 +431,10 @@
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
 	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
 	if (rc) {
@@ -481,6 +488,10 @@
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 
 	rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
 
@@ -527,6 +538,10 @@
 
 	fromName = build_path_from_dentry(source_direntry);
 	toName = build_path_from_dentry(target_direntry);
+	if((fromName == NULL) || (toName == NULL)) {
+		rc = -ENOMEM;
+		goto cifs_rename_exit;
+	}
 
 	rc = CIFSSMBRename(xid, pTcon, fromName, toName,
 			   cifs_sb_source->local_nls);
@@ -549,6 +564,8 @@
 			CIFSSMBClose(xid, pTcon, netfid);
 		}
 	}
+
+cifs_rename_exit:
 	if (fromName)
 		kfree(fromName);
 	if (toName)
@@ -587,6 +604,10 @@
 	cifs_sb = CIFS_SB(direntry->d_sb);
 
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 	cFYI(1,
 	     ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
 	      full_path, direntry->d_inode,
@@ -731,6 +752,10 @@
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 	cifsInode = CIFS_I(direntry->d_inode);
 
 	/* BB check if we need to refresh inode from server now ? BB */
--- diff/fs/cifs/link.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/cifs/link.c	2004-05-27 18:34:18.000000000 +0100
@@ -48,6 +48,11 @@
 
 	fromName = build_path_from_dentry(old_file);
 	toName = build_path_from_dentry(direntry);
+	if((fromName == NULL) || (toName == NULL)) {
+		rc = -ENOMEM;
+		goto cifs_hl_exit;
+	}
+
 	if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
 		rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
 					    cifs_sb_target->local_nls);
@@ -70,6 +75,7 @@
 	cifsInode = CIFS_I(old_file->d_inode);
 	cifsInode->time = 0;	/* will force revalidate to go get info when needed */
 
+cifs_hl_exit:
 	if (fromName)
 		kfree(fromName);
 	if (toName)
@@ -91,6 +97,10 @@
 
 	xid = GetXid();
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
 	cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
@@ -150,6 +160,11 @@
 	pTcon = cifs_sb->tcon;
 
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
+
 	cFYI(1, ("Full path: %s ", full_path));
 	cFYI(1, ("symname is %s", symname));
 
@@ -205,6 +220,11 @@
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 	full_path = build_path_from_dentry(direntry);
+	if(full_path == NULL) {
+		FreeXid(xid);
+		return -ENOMEM;
+	}
+
 	cFYI(1,
 	     ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
 	      full_path, inode, pBuffer, buflen));
--- diff/fs/cifs/transport.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/cifs/transport.c	2004-05-27 18:34:18.000000000 +0100
@@ -187,22 +187,26 @@
 		return -EIO;
 	}
 
+	/* make sure that we sign in the same order that we send on this socket 
+		and avoid races inside tcp sendmsg code that could cause corruption
+		of smb data */
+	down(&ses->server->tcpSem); 
+
 	if (ses->server->tcpStatus == CifsExiting) {
-		return -ENOENT;
+		rc = -ENOENT;
+		goto out_unlock;
 	} else if (ses->server->tcpStatus == CifsNeedReconnect) {
 		cFYI(1,("tcp session dead - return to caller to retry"));
-		return -EAGAIN;
+		rc = -EAGAIN;
+		goto out_unlock;
 	} else if (ses->status != CifsGood) {
 		/* check if SMB session is bad because we are setting it up */
 		if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
 			(in_buf->Command != SMB_COM_NEGOTIATE)) {
-			return -EAGAIN;
+			rc = -EAGAIN;
+			goto out_unlock;
 		} /* else ok - we are setting up session */
 	}
-	/* make sure that we sign in the same order that we send on this socket 
-		and avoid races inside tcp sendmsg code that could cause corruption
-		of smb data */
-	down(&ses->server->tcpSem); 
 	midQ = AllocMidQEntry(in_buf, ses);
 	if (midQ == NULL) {
 		up(&ses->server->tcpSem);
@@ -288,7 +292,6 @@
 		return rc;
 	}
   
-
 	if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
 		cERROR(1,
 		       ("Frame too large received.  Length: %d  Xid: %d",
@@ -342,4 +345,8 @@
 			 - BB add background daemon to clean up Mid entries from
 			 killed processes & test killing process with active mid */
 	return rc;
+
+out_unlock:
+	up(&ses->server->tcpSem);
+	return rc;
 }
--- diff/fs/coda/cnode.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/coda/cnode.c	2004-05-27 18:34:18.000000000 +0100
@@ -17,8 +17,9 @@
 }
 
 static struct inode_operations coda_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.setattr	= coda_setattr,
 };
 
--- diff/fs/compat_ioctl.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/compat_ioctl.c	2004-05-27 18:34:18.000000000 +0100
@@ -3088,6 +3088,189 @@
 	return -EINVAL;
 }
 
+#if defined(CONFIG_NCP_FS) || defined(CONFIG_NCP_FS_MODULE)
+struct ncp_ioctl_request_32 {
+	u32 function;
+	u32 size;
+	compat_caddr_t data;
+};
+
+struct ncp_fs_info_v2_32 {
+	s32 version;
+	u32 mounted_uid;
+	u32 connection;
+	u32 buffer_size;
+
+	u32 volume_number;
+	u32 directory_id;
+
+	u32 dummy1;
+	u32 dummy2;
+	u32 dummy3;
+};
+
+struct ncp_objectname_ioctl_32
+{
+	s32		auth_type;
+	u32		object_name_len;
+	compat_caddr_t	object_name;	/* an userspace data, in most cases user name */
+};
+
+struct ncp_privatedata_ioctl_32
+{
+	u32		len;
+	compat_caddr_t	data;		/* ~1000 for NDS */
+};
+
+#define	NCP_IOC_NCPREQUEST_32		_IOR('n', 1, struct ncp_ioctl_request_32)
+#define NCP_IOC_GETMOUNTUID2_32		_IOW('n', 2, u32)
+#define NCP_IOC_GET_FS_INFO_V2_32	_IOWR('n', 4, struct ncp_fs_info_v2_32)
+#define NCP_IOC_GETOBJECTNAME_32	_IOWR('n', 9, struct ncp_objectname_ioctl_32)
+#define NCP_IOC_SETOBJECTNAME_32	_IOR('n', 9, struct ncp_objectname_ioctl_32)
+#define NCP_IOC_GETPRIVATEDATA_32	_IOWR('n', 10, struct ncp_privatedata_ioctl_32)
+#define NCP_IOC_SETPRIVATEDATA_32	_IOR('n', 10, struct ncp_privatedata_ioctl_32)
+
+static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_ioctl_request_32 n32;
+	struct ncp_ioctl_request *p = compat_alloc_user_space(sizeof(*p));
+
+	if (copy_from_user(&n32, compat_ptr(arg), sizeof(n32)) ||
+	    put_user(n32.function, &p->function) ||
+	    put_user(n32.size, &p->size) ||
+	    put_user(compat_ptr(n32.data), &p->data))
+		return -EFAULT;
+
+	return sys_ioctl(fd, NCP_IOC_NCPREQUEST, (unsigned long)p);
+}
+
+static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	__kernel_uid_t kuid;
+	int err;
+
+	cmd = NCP_IOC_GETMOUNTUID2;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
+	set_fs(old_fs);
+
+	if (!err)
+		err = put_user(kuid, (unsigned int *)compat_ptr(arg));
+
+	return err;
+}
+
+static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct ncp_fs_info_v2_32 n32;
+	struct ncp_fs_info_v2 n;
+	int err;
+
+	if (copy_from_user(&n32, compat_ptr(arg), sizeof(n32)))
+		return -EFAULT;
+	if (n32.version != NCP_GET_FS_INFO_VERSION_V2)
+		return -EINVAL;
+	n.version = NCP_GET_FS_INFO_VERSION_V2;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n);
+	set_fs(old_fs);
+
+	if (!err) {
+		n32.version = n.version;
+		n32.mounted_uid = n.mounted_uid;
+		n32.connection = n.connection;
+		n32.buffer_size = n.buffer_size;
+		n32.volume_number = n.volume_number;
+		n32.directory_id = n.directory_id;
+		n32.dummy1 = n.dummy1;
+		n32.dummy2 = n.dummy2;
+		n32.dummy3 = n.dummy3;
+		err = copy_to_user(compat_ptr(arg), &n32, sizeof(n32)) ? -EFAULT : 0;
+	}
+	return err;
+}
+
+static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_objectname_ioctl_32 n32, *p32 = compat_ptr(arg);
+	struct ncp_objectname_ioctl *p = compat_alloc_user_space(sizeof(*p));
+	s32 auth_type;
+	u32 name_len;
+	int err;
+
+	if (copy_from_user(&n32, p32, sizeof(n32)) ||
+	    put_user(n32.object_name_len, &p->object_name_len) ||
+	    put_user(compat_ptr(n32.object_name), &p->object_name))
+		return -EFAULT;
+
+	err = sys_ioctl(fd, NCP_IOC_GETOBJECTNAME, (unsigned long)p);
+        if (err)
+		return err;
+
+	if (get_user(auth_type, &p->auth_type) ||
+	    put_user(auth_type, &p32->auth_type) ||
+	    get_user(name_len, &p->object_name_len) ||
+	    put_user(name_len, &p32->object_name_len))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_objectname_ioctl_32 n32, *p32 = compat_ptr(arg);
+	struct ncp_objectname_ioctl *p = compat_alloc_user_space(sizeof(*p));
+
+	if (copy_from_user(&n32, p32, sizeof(n32)) ||
+	    put_user(n32.auth_type, &p->auth_type) ||
+	    put_user(n32.object_name_len, &p->object_name_len) ||
+	    put_user(compat_ptr(n32.object_name), &p->object_name))
+		return -EFAULT;
+
+	return sys_ioctl(fd, NCP_IOC_SETOBJECTNAME, (unsigned long)p);
+}
+
+static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_privatedata_ioctl_32 n32, *p32 = compat_ptr(arg);
+	struct ncp_privatedata_ioctl *p = compat_alloc_user_space(sizeof(*p));
+	u32 len;
+	int err;
+
+	if (copy_from_user(&n32, p32, sizeof(n32)) ||
+	    put_user(n32.len, &p->len) ||
+	    put_user(compat_ptr(n32.data), &p->data))
+		return -EFAULT;
+
+	err = sys_ioctl(fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)p);
+        if (err)
+		return err;
+
+	if (get_user(len, &p->len) ||
+	    put_user(len, &p32->len))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_privatedata_ioctl_32 n32, *p32 = compat_ptr(arg);
+	struct ncp_privatedata_ioctl *p = compat_alloc_user_space(sizeof(*p));
+
+	if (copy_from_user(&n32, p32, sizeof(n32)) ||
+	    put_user(n32.len, &p->len) ||
+	    put_user(compat_ptr(n32.data), &p->data))
+		return -EFAULT;
+
+	return sys_ioctl(fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)p);
+}
+#endif
+
 #undef CODE
 #endif
 
@@ -3270,5 +3453,15 @@
 HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
 HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
 
+#if defined(CONFIG_NCP_FS) || defined(CONFIG_NCP_FS_MODULE)
+HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest)
+HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2)
+HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2)
+HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname)
+HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname)
+HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata)
+HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
+#endif
+
 #undef DECLARES
 #endif
--- diff/fs/dcache.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/dcache.c	2004-05-27 18:34:18.000000000 +0100
@@ -846,7 +846,12 @@
 			res->d_sb = inode->i_sb;
 			res->d_parent = res;
 			res->d_inode = inode;
-			res->d_bucket = d_hash(res, res->d_name.hash);
+
+			/*
+			 * Set d_bucket to an "impossible" bucket address so
+			 * that d_move() doesn't get a false positive
+			 */
+			res->d_bucket = dentry_hashtable + D_HASHMASK + 1;
 			res->d_flags |= DCACHE_DISCONNECTED;
 			res->d_flags &= ~DCACHE_UNHASHED;
 			list_add(&res->d_alias, &inode->i_dentry);
--- diff/fs/devfs/base.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/devfs/base.c	2004-05-27 18:34:18.000000000 +0100
@@ -2490,28 +2490,11 @@
 	return 0;
 }				/*  End Function devfs_mknod  */
 
-static int devfs_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	int err;
-	struct devfs_entry *de;
-
-	de = get_devfs_entry_from_vfs_inode(dentry->d_inode);
-	if (!de)
-		return -ENODEV;
-	err = vfs_readlink(dentry, buffer, buflen, de->u.symlink.linkname);
-	return err;
-}				/*  End Function devfs_readlink  */
-
 static int devfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	int err;
-	struct devfs_entry *de;
-
-	de = get_devfs_entry_from_vfs_inode(dentry->d_inode);
-	if (!de)
-		return -ENODEV;
-	err = vfs_follow_link(nd, de->u.symlink.linkname);
-	return err;
+	struct devfs_entry *p = get_devfs_entry_from_vfs_inode(dentry->d_inode);
+	nd_set_link(nd, p ? p->u.symlink.linkname : ERR_PTR(-ENODEV));
+	return 0;
 }				/*  End Function devfs_follow_link  */
 
 static struct inode_operations devfs_iops = {
@@ -2529,7 +2512,7 @@
 };
 
 static struct inode_operations devfs_symlink_iops = {
-	.readlink = devfs_readlink,
+	.readlink = generic_readlink,
 	.follow_link = devfs_follow_link,
 	.setattr = devfs_notify_change,
 };
--- diff/fs/eventpoll.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/eventpoll.c	2004-05-27 18:34:18.000000000 +0100
@@ -148,14 +148,6 @@
 #define EP_ITEM_FROM_EPQUEUE(p) (container_of(p, struct ep_pqueue, pt)->epi)
 
 /*
- * This is used to optimize the event transfer to userspace. Since this
- * is kept on stack, it should be pretty small.
- */
-#define EP_MAX_BUF_EVENTS 32
-
-
-
-/*
  * Node that is linked into the "wake_task_list" member of the "struct poll_safewake".
  * It is used to keep track on all tasks that are currently inside the wake_up() code
  * to 1) short-circuit the one coming from the same task and same wait queue head
@@ -1430,11 +1422,10 @@
 static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
 			  struct epoll_event __user *events)
 {
-	int eventcnt = 0, eventbuf = 0;
+	int eventcnt = 0;
 	unsigned int revents;
 	struct list_head *lnk;
 	struct epitem *epi;
-	struct epoll_event event[EP_MAX_BUF_EVENTS];
 
 	/*
 	 * We can loop without lock because this is a task private list.
@@ -1460,28 +1451,17 @@
 		epi->revents = revents & epi->event.events;
 
 		if (epi->revents) {
-			event[eventbuf] = epi->event;
-			event[eventbuf].events &= revents;
-			eventbuf++;
-			if (eventbuf == EP_MAX_BUF_EVENTS) {
-				if (__copy_to_user(&events[eventcnt], event,
-						   eventbuf * sizeof(struct epoll_event)))
-					return -EFAULT;
-				eventcnt += eventbuf;
-				eventbuf = 0;
-			}
+			if (__put_user(epi->event.events,
+					&events[eventcnt].events))
+				return -EFAULT;
+			if (__put_user(epi->event.data,
+					&events[eventcnt].data))
+				return -EFAULT;
 			if (epi->event.events & EPOLLONESHOT)
 				epi->event.events &= EP_PRIVATE_BITS;
+			eventcnt++;
 		}
 	}
-
-	if (eventbuf) {
-		if (__copy_to_user(&events[eventcnt], event,
-				   eventbuf * sizeof(struct epoll_event)))
-			return -EFAULT;
-		eventcnt += eventbuf;
-	}
-
 	return eventcnt;
 }
 
--- diff/fs/exec.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/exec.c	2004-05-27 18:34:18.000000000 +0100
@@ -48,7 +48,6 @@
 #include <linux/rmap.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 
 #ifdef CONFIG_KMOD
@@ -839,7 +838,8 @@
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL))
+	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) ||
+	    (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP))
 		current->mm->dumpable = 0;
 
 	/* An exec changes our domain. We are no longer part of the thread
@@ -1088,6 +1088,7 @@
 	bprm.file = file;
 	bprm.filename = filename;
 	bprm.interp = filename;
+	bprm.interp_flags = 0;
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
--- diff/fs/ext2/ialloc.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext2/ialloc.c	2004-05-27 18:34:18.000000000 +0100
@@ -663,7 +663,7 @@
 	}
 	brelse(bitmap_bh);
 	printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
-		percpu_counter_read(EXT2_SB(sb)->s_freeinodes_counter),
+		percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter),
 		desc_count, bitmap_count);
 	unlock_super(sb);
 	return desc_count;
@@ -724,7 +724,7 @@
 		bitmap_count += x;
 	}
 	brelse(bitmap_bh);
-	if (percpu_counter_read(EXT2_SB(sb)->s_freeinodes_counter) !=
+	if (percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter) !=
 				bitmap_count)
 		ext2_error(sb, "ext2_check_inodes_bitmap",
 			    "Wrong free inodes count in super block, "
--- diff/fs/ext2/symlink.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext2/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -20,22 +20,17 @@
 #include "ext2.h"
 #include "xattr.h"
 
-static int
-ext2_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
-	return vfs_readlink(dentry, buffer, buflen, (char *)ei->i_data);
-}
-
 static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
-	return vfs_follow_link(nd, (char *)ei->i_data);
+	nd_set_link(nd, (char *)ei->i_data);
+	return 0;
 }
 
 struct inode_operations ext2_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.setxattr	= ext2_setxattr,
 	.getxattr	= ext2_getxattr,
 	.listxattr	= ext2_listxattr,
@@ -43,7 +38,7 @@
 };
  
 struct inode_operations ext2_fast_symlink_inode_operations = {
-	.readlink	= ext2_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= ext2_follow_link,
 	.setxattr	= ext2_setxattr,
 	.getxattr	= ext2_getxattr,
--- diff/fs/ext3/acl.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/acl.c	2004-05-27 18:34:18.000000000 +0100
@@ -428,7 +428,9 @@
 	error = posix_acl_chmod_masq(clone, inode->i_mode);
 	if (!error) {
 		handle_t *handle;
+		int retries = 0;
 
+	retry:
 		handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
 		if (IS_ERR(handle)) {
 			error = PTR_ERR(handle);
@@ -437,6 +439,9 @@
 		}
 		error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone);
 		ext3_journal_stop(handle);
+		if (error == -ENOSPC &&
+		    ext3_should_retry_alloc(inode->i_sb, &retries))
+			goto retry;
 	}
 out:
 	posix_acl_release(clone);
@@ -516,7 +521,7 @@
 {
 	handle_t *handle;
 	struct posix_acl *acl;
-	int error;
+	int error, retries = 0;
 
 	if (!test_opt(inode->i_sb, POSIX_ACL))
 		return -EOPNOTSUPP;
@@ -535,11 +540,14 @@
 	} else
 		acl = NULL;
 
+retry:
 	handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
 	error = ext3_set_acl(handle, inode, type, acl);
 	ext3_journal_stop(handle);
+	if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
+		goto retry;
 
 release_and_out:
 	posix_acl_release(acl);
--- diff/fs/ext3/balloc.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/balloc.c	2004-05-27 18:34:18.000000000 +0100
@@ -96,9 +96,87 @@
 error_out:
 	return bh;
 }
+/*
+ * The reservation window structure operations
+ * --------------------------------------------
+ * Operations include:
+ * dump, find, add, remove, is_empty, find_next_reservable_window, etc.
+ *
+ * We use sorted double linked list for the per-filesystem reservation
+ * window list. (like in vm_region).
+ *
+ * Initially, we keep those small operations in the abstract functions,
+ * so later if we need a better searching tree than double linked-list,
+ * we could easily switch to that without changing too much
+ * code.
+ */
+static inline void rsv_window_dump(struct reserve_window *head, char *fn)
+{
+	struct reserve_window *rsv;
+
+	printk("Block Allocation Reservation Windows Map (%s):\n", fn);
+	list_for_each_entry(rsv, &head->rsv_list, rsv_list) {
+		printk("reservation window 0x%p start:  %d, end:  %d\n",
+			 rsv, rsv->rsv_start, rsv->rsv_end);
+	}
+}
+
+static int
+goal_in_my_reservation(struct reserve_window *rsv, int goal,
+			unsigned int group, struct super_block * sb)
+{
+	unsigned long group_first_block, group_last_block;
+
+	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+				group * EXT3_BLOCKS_PER_GROUP(sb);
+	group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
+
+	if ((rsv->rsv_start > group_last_block) ||
+	    (rsv->rsv_end < group_first_block))
+		return 0;
+	if ((goal >= 0) && ((goal + group_first_block < rsv->rsv_start)
+		|| (goal + group_first_block > rsv->rsv_end)))
+		return 0;
+	return 1;
+}
+
+static inline void rsv_window_add(struct reserve_window *rsv,
+					struct reserve_window *prev)
+{
+	/* insert the new reservation window after the head */
+	list_add(&rsv->rsv_list, &prev->rsv_list);
+}
+
+static inline void rsv_window_remove(struct reserve_window *rsv)
+{
+	rsv->rsv_start = 0;
+	rsv->rsv_end = 0;
+		rsv->rsv_alloc_hit = 0;
+	list_del(&rsv->rsv_list);
+	INIT_LIST_HEAD(&rsv->rsv_list);
+}
+
+static inline int rsv_is_empty(struct reserve_window *rsv)
+{
+	/* a valid reservation end block could not be 0 */
+	return (rsv->rsv_end == 0);
+}
+
+void ext3_discard_reservation(struct inode *inode)
+{
+	struct ext3_inode_info *ei = EXT3_I(inode);
+	struct reserve_window *rsv = &ei->i_rsv_window;
+	spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock;
+
+	if (!rsv_is_empty(rsv)) {
+		spin_lock(rsv_lock);
+		rsv_window_remove(rsv);
+		spin_unlock(rsv_lock);
+	}
+}
 
 /* Free given blocks, update quota and i_blocks field */
-void ext3_free_blocks (handle_t *handle, struct inode * inode,
+void ext3_free_blocks(handle_t *handle, struct inode *inode,
 			unsigned long block, unsigned long count)
 {
 	struct buffer_head *bitmap_bh = NULL;
@@ -296,7 +374,7 @@
  * data-writes at some point, and disable it for metadata allocations or
  * sync-data inodes.
  */
-static inline int ext3_test_allocatable(int nr, struct buffer_head *bh)
+static int ext3_test_allocatable(int nr, struct buffer_head *bh)
 {
 	int ret;
 	struct journal_head *jh = bh2jh(bh);
@@ -313,6 +391,33 @@
 	return ret;
 }
 
+static int
+bitmap_search_next_usable_block(int start, struct buffer_head *bh,
+					int maxblocks)
+{
+	int next;
+	struct journal_head *jh = bh2jh(bh);
+
+	/*
+	 * The bitmap search --- search forward alternately through the actual
+	 * bitmap and the last-committed copy until we find a bit free in
+	 * both
+	 */
+	while (start < maxblocks) {
+		next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start);
+		if (next >= maxblocks)
+			return -1;
+		if (ext3_test_allocatable(next, bh))
+			return next;
+		jbd_lock_bh_state(bh);
+		if (jh->b_committed_data)
+			start = ext3_find_next_zero_bit(jh->b_committed_data,
+						 	maxblocks, next);
+		jbd_unlock_bh_state(bh);
+	}
+	return -1;
+}
+
 /*
  * Find an allocatable block in a bitmap.  We honour both the bitmap and
  * its last-committed copy (if that exists), and perform the "most
@@ -325,7 +430,6 @@
 {
 	int here, next;
 	char *p, *r;
-	struct journal_head *jh = bh2jh(bh);
 
 	if (start > 0) {
 		/*
@@ -337,6 +441,8 @@
 		 * next 64-bit boundary is simple..
 		 */
 		int end_goal = (start + 63) & ~63;
+		if (end_goal > maxblocks)
+			end_goal = maxblocks;
 		here = ext3_find_next_zero_bit(bh->b_data, end_goal, start);
 		if (here < end_goal && ext3_test_allocatable(here, bh))
 			return here;
@@ -351,7 +457,7 @@
 	r = memscan(p, 0, (maxblocks - here + 7) >> 3);
 	next = (r - ((char *)bh->b_data)) << 3;
 
-	if (next < maxblocks && ext3_test_allocatable(next, bh))
+	if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh))
 		return next;
 
 	/*
@@ -359,19 +465,8 @@
 	 * bitmap and the last-committed copy until we find a bit free in
 	 * both
 	 */
-	while (here < maxblocks) {
-		next = ext3_find_next_zero_bit(bh->b_data, maxblocks, here);
-		if (next >= maxblocks)
-			return -1;
-		if (ext3_test_allocatable(next, bh))
-			return next;
-		jbd_lock_bh_state(bh);
-		if (jh->b_committed_data)
-			here = ext3_find_next_zero_bit(jh->b_committed_data,
-						 	maxblocks, next);
-		jbd_unlock_bh_state(bh);
-	}
-	return -1;
+	here = bitmap_search_next_usable_block(here, bh, maxblocks);
+	return here;
 }
 
 /*
@@ -407,62 +502,494 @@
  */
 static int
 ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
-		struct buffer_head *bitmap_bh, int goal, int *errp)
+	struct buffer_head *bitmap_bh, int goal, struct reserve_window *my_rsv)
 {
-	int i;
-	int fatal;
-	int credits = 0;
+	int group_first_block, start, end;
 
-	*errp = 0;
-
-	/*
-	 * Make sure we use undo access for the bitmap, because it is critical
-	 * that we do the frozen_data COW on bitmap buffers in all cases even
-	 * if the buffer is in BJ_Forget state in the committing transaction.
-	 */
-	BUFFER_TRACE(bitmap_bh, "get undo access for new block");
-	fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
-	if (fatal) {
-		*errp = fatal;
-		goto fail;
+	/* we do allocation within the reservation window if we have a window */
+	if (my_rsv) {
+		group_first_block =
+			le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+			group * EXT3_BLOCKS_PER_GROUP(sb);
+		if (my_rsv->rsv_start >= group_first_block)
+			start = my_rsv->rsv_start - group_first_block;
+		else
+			/* reservation window cross group boundary */
+			start = 0;
+		end = my_rsv->rsv_end - group_first_block + 1;
+		if (end > EXT3_BLOCKS_PER_GROUP(sb))
+			/* reservation window crosses group boundary */
+			end = EXT3_BLOCKS_PER_GROUP(sb);
+		if ((start <= goal) && (goal < end))
+			start = goal;
+		else
+			goal = -1;
+	} else {
+		if (goal > 0)
+			start = goal;
+		else
+			start = 0;
+		end = EXT3_BLOCKS_PER_GROUP(sb);
 	}
 
+	BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb));
+
 repeat:
 	if (goal < 0 || !ext3_test_allocatable(goal, bitmap_bh)) {
-		goal = find_next_usable_block(goal, bitmap_bh,
-					EXT3_BLOCKS_PER_GROUP(sb));
+		goal = find_next_usable_block(start, bitmap_bh, end);
 		if (goal < 0)
 			goto fail_access;
+		if (!my_rsv) {
+			int i;
 
-		for (i = 0; i < 7 && goal > 0 &&
-				ext3_test_allocatable(goal - 1, bitmap_bh);
-			i++, goal--);
+			for (i = 0; i < 7 && goal > start &&
+					ext3_test_allocatable(goal - 1,
+								bitmap_bh);
+					i++, goal--)
+				;
+		}
 	}
+	start = goal;
 
 	if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
 		/*
 		 * The block was allocated by another thread, or it was
 		 * allocated and then freed by another thread
 		 */
+		start++;
 		goal++;
-		if (goal >= EXT3_BLOCKS_PER_GROUP(sb))
+		if (start >= end)
 			goto fail_access;
 		goto repeat;
 	}
+	if (my_rsv)
+		my_rsv->rsv_alloc_hit++;
+	return goal;
+fail_access:
+	return -1;
+}
+
+/**
+ * 	find_next_reservable_window():
+ *		find a reservable space within the given range
+ *		It does not allocate the reservation window for now
+ *		alloc_new_reservation() will do the work later.
+ *
+ * 	@search_head: the head of the searching list;
+ *		This is not necessary the list head of the whole filesystem
+ *
+ *		we have both head and start_block to assist the search
+ *		for the reservable space. The list start from head,
+ *		but we will shift to the place where start_block is,
+ *		then start from there, we looking for a resevable space.
+ *
+ *	@fs_rsv_head: per-filesystem reervation list head.
+ *
+ * 	@size: the target new reservation window size
+ * 	@group_first_block: the first block we consider to start
+ *			the real search from
+ *
+ * 	@last_block:
+ *		the maxium block number that our goal reservable space
+ *		could start from. This is normally the last block in this
+ *		group. The search will end when we found the start of next
+ *		possiblereservable space is out of this boundary.
+ *		This could handle the cross bounday reservation window request.
+ *
+ * 	basically we search from the given range, rather than the whole
+ * 	reservation double linked list, (start_block, last_block)
+ * 	to find a free region that of of my size and has not
+ * 	been reserved.
+ *
+ *	on succeed, it returns the reservation window to be append to.
+ *	failed, return NULL.
+ */
+static inline
+struct reserve_window *find_next_reservable_window(
+				struct reserve_window *search_head,
+				struct reserve_window *fs_rsv_head,
+				unsigned long size, int *start_block,
+				int last_block)
+{
+	struct reserve_window *rsv;
+	int cur;
+
+	/* TODO:make the start of the reservation window byte alligned */
+	/*cur = *start_block & 8;*/
+	cur = *start_block;
+	rsv = list_entry(search_head->rsv_list.next,
+				struct reserve_window, rsv_list);
+	while (rsv != fs_rsv_head) {
+		if (cur + size <= rsv->rsv_start) {
+	 		/*
+			 * Found a reserveable space big enough.  We could
+			 * have a reservation across the group boundary here
+		 	 */
+			break;
+		}
+		if (cur <= rsv->rsv_end)
+			cur = rsv->rsv_end + 1;
+
+		/* TODO?
+		 * in the case we could not find a reservable space
+		 * that is what is expected, during the re-search, we could
+		 * remember what's the largest reservable space we could have
+		 * and return that one.
+		 *
+		 * For now it will fail if we could not find the reservable
+		 * space with expected-size (or more)...
+		 */
+		rsv = list_entry(rsv->rsv_list.next,
+				struct reserve_window, rsv_list);
+		if (cur > last_block)
+			return NULL;		/* fail */
+	}
+	/*
+	 * we come here either :
+	 * when we rearch to the end of the whole list,
+	 * and there is empty reservable space after last entry in the list.
+	 * append it to the end of the list.
+	 *
+	 * or we found one reservable space in the middle of the list,
+	 * return the reservation window that we could append to.
+	 * succeed.
+	 */
+	*start_block = cur;
+	return list_entry(rsv->rsv_list.prev, struct reserve_window, rsv_list);
+}
+
+/**
+ * 	alloc_new_reservation()--allocate a new reservation window
+ *		if there is an existing reservation, discard it first
+ *		then allocate the new one from there
+ *		otherwise allocate the new reservation from the given
+ *		start block, or the beginning of the group, if a goal
+ *		is not given.
+ *
+ *		To make a new reservation, we search part of the filesystem
+ *		reservation list(the list that inside the group).
+ *
+ *		If we have a old reservation, the search goal is the end of
+ *		last reservation. If we do not have a old reservatio, then we
+ *		start from a given goal, or the first block of the group, if
+ *		the goal is not given.
+ *
+ *		We first find a reservable space after the goal, then from
+ *		there,we check the bitmap for the first free block after
+ *		it. If there is no free block until the end of group, then the
+ *		whole group is full, we failed. Otherwise, check if the free
+ *		block is inside the expected reservable space, if so, we
+ *		succeed.
+ *		If the first free block is outside the reseravle space, then
+ *		start from the first free block, we search for next avalibale
+ *		space, and go on.
+ *
+ *	on succeed, a new reservation will be found and inserted into the list
+ *	It contains at least one free block, and it is not overlap with other
+ *	reservation window.
+ *
+ *	failed: we failed to found a reservation window in this group
+ *
+ *	@rsv: the reservation
+ *
+ *	@goal: The goal.  It is where the search for a
+ *		free reservable space should start from.
+ *		if we have a old reservation, start_block is the end of
+ *		old reservation. Otherwise,
+ *		if we have a goal(goal >0 ), then start from there,
+ *		no goal(goal = -1), we start from the first block
+ *		of the group.
+ *
+ *	@sb: the super block
+ *	@group: the group we are trying to do allocate in
+ *	@bitmap_bh: the block group block bitmap
+ */
+static int alloc_new_reservation(struct reserve_window *my_rsv,
+		int goal, struct super_block *sb,
+		unsigned int group, struct buffer_head *bitmap_bh)
+{
+	struct reserve_window *search_head;
+	int group_first_block, group_end_block, start_block;
+	int first_free_block;
+	int reservable_space_start;
+	struct reserve_window *prev_rsv;
+	struct reserve_window *fs_rsv_head = &EXT3_SB(sb)->s_rsv_window_head;
+	unsigned long size;
+
+	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+				group * EXT3_BLOCKS_PER_GROUP(sb);
+	group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
+
+	if (goal < 0)
+		start_block = group_first_block;
+	else
+		start_block = goal + group_first_block;
+
+	size = atomic_read(&my_rsv->rsv_goal_size);
+	/* if we have a old reservation, start the search from the old rsv */
+	if (!rsv_is_empty(my_rsv)) {
+		/*
+		 * if the old reservation is cross group boundary
+		 * we will come here when we just failed to allocate from
+		 * the first part of the window. We still have another part
+		 * that belongs to the next group. In this case, there is no
+		 * point to discard our window and try to allocate a new one
+		 * in this group(which will fail). we should
+		 * keep the reservation window, just simply move on.
+		 *
+		 * Maybe we could shift the start block of the reservation
+		 * window to the first block of next group.
+		 */
+
+		if ((my_rsv->rsv_start <= group_end_block) &&
+				(my_rsv->rsv_end > group_end_block))
+			return -1;
+
+		/* remember where we are before we discard the old one */
+		if (my_rsv->rsv_end + 1 > start_block)
+			start_block = my_rsv->rsv_end + 1;
+		search_head = my_rsv;
+		if ((my_rsv->rsv_alloc_hit > (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
+			/*
+			 * if we previously allocation hit ration is greater than half
+			 * we double the size of reservation window next time
+			 * otherwise keep the same
+			 */
+			size = size * 2;
+			if (size > EXT3_MAX_RESERVE_BLOCKS)
+				size = EXT3_MAX_RESERVE_BLOCKS;
+			atomic_set(&my_rsv->rsv_goal_size, size);
+		}
+	}
+	else {
+		/*
+		 * we don't have a reservation,
+		 * we set our goal(start_block) and
+		 * the list head for the search
+		 */
+		search_head = fs_rsv_head;
+	}
+
+	/*
+	 * find_next_reservable_window() simply find a reservable window
+	 * inside the given range(start_block, group_end_block).
+	 *
+	 * To make sure the reservation window has a free bit inside it, we
+	 * need to check the bitmap after we found a reservable window.
+	 */
+retry:
+	prev_rsv = find_next_reservable_window(search_head, fs_rsv_head, size,
+						&start_block, group_end_block);
+	if (prev_rsv == NULL)
+		goto failed;
+	reservable_space_start = start_block;
+	/*
+	 * On success, find_next_reservable_window() returns the
+	 * reservation window where there is a reservable space after it.
+	 * Before we reserve this reservable space, we need
+	 * to make sure there is at least a free block inside this region.
+	 *
+	 * searching the first free bit on the block bitmap and copy of
+	 * last committed bitmap alternatively, until we found a allocatable
+	 * block. Search start from the start block of the reservable space
+	 * we just found.
+	 */
+	first_free_block = bitmap_search_next_usable_block(
+			reservable_space_start - group_first_block,
+			bitmap_bh, group_end_block - group_first_block + 1);
 
-	BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block");
-	fatal = ext3_journal_dirty_metadata(handle, bitmap_bh);
+	if (first_free_block < 0) {
+		/*
+		 * no free block left on the bitmap, no point
+		 * to reserve the space. return failed.
+		 */
+		goto failed;
+	}
+	start_block = first_free_block + group_first_block;
+	/*
+	 * check if the first free block is within the
+	 * free space we just found
+	 */
+	if ((start_block >= reservable_space_start) &&
+	  (start_block < reservable_space_start + size))
+		goto found_rsv_window;
+	/*
+	 * if the first free bit we found is out of the reservable space
+	 * this means there is no free block on the reservable space
+	 * we should continue search for next reservable space,
+	 * start from where the free block is,
+	 * we also shift the list head to where we stopped last time
+	 */
+	search_head = prev_rsv;
+	goto retry;
+
+found_rsv_window:
+	/*
+	 * great! the reservable space contains some free blocks.
+	 * if the search returns that we should add the new
+	 * window just next to where the old window, we don't
+ 	 * need to remove the old window first then add it to the
+	 * same place, just update the new start and new end.
+	 */
+	if (my_rsv != prev_rsv)  {
+		if (!rsv_is_empty(my_rsv))
+			rsv_window_remove(my_rsv);
+		rsv_window_add(my_rsv, prev_rsv);
+	}
+	my_rsv->rsv_start = reservable_space_start;
+	my_rsv->rsv_end = my_rsv->rsv_start + size - 1;
+	return 0;		/* succeed */
+failed:
+	return -1;		/* failed */
+}
+
+/*
+ * This is the main function used to allocate a new block and its reservation
+ * window.
+ *
+ * Each time when a new block allocation is need, first try to allocate from
+ * its own reservation.  If it does not have a reservation window, instead of
+ * looking for a free bit on bitmap first, then look up the reservation list to
+ * see if it is inside somebody else's reservation window, we try to allocate a
+ * reservation window for it start from the goal first. Then do the block
+ * allocation within the reservation window.
+ *
+ * This will aviod keep searching the reservation list again and again when
+ * someboday is looking for a free block(without reservation), and there are
+ * lots of free blocks, but they are all being reserved
+ *
+ * We use a sorted double linked list for the per-filesystem reservation list.
+ * The insert, remove and find a free space(non-reserved) operations for the
+ * sorted double linked list should be fast.
+ *
+ */
+static int
+ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
+			unsigned int group, struct buffer_head *bitmap_bh,
+			int goal, struct reserve_window * my_rsv,
+			int *errp)
+{
+	spinlock_t *rsv_lock;
+	unsigned long group_first_block;
+	int ret = 0;
+	int fatal;
+	int credits = 0;
+
+	*errp = 0;
+
+	/*
+	 * Make sure we use undo access for the bitmap, because it is critical
+	 * that we do the frozen_data COW on bitmap buffers in all cases even
+	 * if the buffer is in BJ_Forget state in the committing transaction.
+	 */
+	BUFFER_TRACE(bitmap_bh, "get undo access for new block");
+	fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
 	if (fatal) {
 		*errp = fatal;
-		goto fail;
+		return -1;
+	}
+
+	/*
+	 * we don't deal with reservation when
+	 * filesystem is mounted without reservation
+	 * or the file is not a regular file
+	 * of last attemp of allocating a block with reservation turn on failed
+	 */
+	if (my_rsv == NULL ) {
+		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL);
+		goto out;
+	}
+	rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
+	/*
+	 * goal is a group relative block number (if there is a goal)
+	 * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb)
+	 * first block is a filesystem wide block number
+	 * first block is the block number of the first block in this group
+	 */
+	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+			group * EXT3_BLOCKS_PER_GROUP(sb);
+
+	/*
+	 * Basically we will allocate a new block from inode's reservation
+	 * window.
+	 *
+	 * We need to allocate a new reservation window, if:
+	 * a) inode does not have a reservation window; or
+	 * b) last attemp of allocating a block from existing reservation
+	 *    failed; or
+	 * c) we come here with a goal and with a reservation window
+	 *
+	 * We do not need to allocate a new reservation window if we come here
+	 * at the beginning with a goal and the goal is inside the window, or
+	 * or we don't have a goal but already have a reservation window.
+	 * then we could go to allocate from the reservation window directly.
+	 */
+	while (1) {
+		if (rsv_is_empty(my_rsv) || (ret < 0) ||
+			!goal_in_my_reservation(my_rsv, goal, group, sb)) {
+			spin_lock(rsv_lock);
+			ret = alloc_new_reservation(my_rsv, goal, sb,
+							group, bitmap_bh);
+			spin_unlock(rsv_lock);
+			if (ret < 0)
+				break;			/* failed */
+
+			if (!goal_in_my_reservation(my_rsv, goal, group, sb))
+				goal = -1;
+		}
+		if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
+			|| (my_rsv->rsv_end < group_first_block))
+			BUG();
+		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
+					my_rsv);
+		if (ret >= 0)
+			break;				/* succeed */
+	}
+out:
+	if (ret >= 0) {
+		BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for "
+					"bitmap block");
+		fatal = ext3_journal_dirty_metadata(handle, bitmap_bh);
+		if (fatal) {
+			*errp = fatal;
+			return -1;
+		}
+		return ret;
 	}
-	return goal;
 
-fail_access:
 	BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
 	ext3_journal_release_buffer(handle, bitmap_bh, credits);
-fail:
-	return -1;
+	return ret;
+}
+
+static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
+{
+	int free_blocks, root_blocks;
+
+	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
+	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
+	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
+		sbi->s_resuid != current->fsuid &&
+		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * ext3_should_retry_alloc() is called when ENOSPC is returned, and if
+ * it is profitable to retry the operation, this function will wait
+ * for the current or commiting transaction to complete, and then
+ * return TRUE.
+ */
+int ext3_should_retry_alloc(struct super_block *sb, int *retries)
+{
+	if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3)
+		return 0;
+
+	jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
+
+	return journal_force_commit_nested(EXT3_SB(sb)->s_journal);
 }
 
 /*
@@ -473,23 +1000,24 @@
  * bitmap, and then for any free bit if that fails.
  * This function also updates quota and i_blocks field.
  */
-int
-ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal,
-		u32 *prealloc_count, u32 *prealloc_block, int *errp)
-{
-	struct buffer_head *bitmap_bh = NULL;	/* bh */
-	struct buffer_head *gdp_bh;		/* bh2 */
-	int group_no;				/* i */
-	int ret_block;				/* j */
-	int bgi;				/* blockgroup iteration index */
-	int target_block;			/* tmp */
+int ext3_new_block(handle_t *handle, struct inode *inode,
+			unsigned long goal, int *errp)
+{
+	struct buffer_head *bitmap_bh = NULL;
+	struct buffer_head *gdp_bh;
+	int group_no;
+	int goal_group;
+	int ret_block;
+	int bgi;			/* blockgroup iteration index */
+	int target_block;
 	int fatal = 0, err;
 	int performed_allocation = 0;
-	int free_blocks, root_blocks;
+	int free_blocks;
 	struct super_block *sb;
 	struct ext3_group_desc *gdp;
 	struct ext3_super_block *es;
 	struct ext3_sb_info *sbi;
+	struct reserve_window *my_rsv = NULL;
 #ifdef EXT3FS_DEBUG
 	static int goal_hits, goal_attempts;
 #endif
@@ -511,12 +1039,9 @@
 	sbi = EXT3_SB(sb);
 	es = EXT3_SB(sb)->s_es;
 	ext3_debug("goal=%lu.\n", goal);
-
-	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
-	root_blocks = le32_to_cpu(es->s_r_blocks_count);
-	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
-		sbi->s_resuid != current->fsuid &&
-		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+	if (test_opt(sb, RESERVATION) && S_ISREG(inode->i_mode))
+		my_rsv = &EXT3_I(inode)->i_rsv_window;
+	if (!ext3_has_free_blocks(sbi)) {
 		*errp = -ENOSPC;
 		goto out;
 	}
@@ -533,6 +1058,8 @@
 	if (!gdp)
 		goto io_error;
 
+	goal_group = group_no;
+retry:
 	free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
 	if (free_blocks > 0) {
 		ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %
@@ -540,8 +1067,8 @@
 		bitmap_bh = read_block_bitmap(sb, group_no);
 		if (!bitmap_bh)
 			goto io_error;
-		ret_block = ext3_try_to_allocate(sb, handle, group_no,
-					bitmap_bh, ret_block, &fatal);
+		ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
+					bitmap_bh, ret_block, my_rsv, &fatal);
 		if (fatal)
 			goto out;
 		if (ret_block >= 0)
@@ -569,14 +1096,25 @@
 		bitmap_bh = read_block_bitmap(sb, group_no);
 		if (!bitmap_bh)
 			goto io_error;
-		ret_block = ext3_try_to_allocate(sb, handle, group_no,
-						bitmap_bh, -1, &fatal);
+		ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
+					bitmap_bh, -1, my_rsv, &fatal);
 		if (fatal)
 			goto out;
 		if (ret_block >= 0) 
 			goto allocated;
 	}
-
+	/*
+	 * We may end up a bogus ealier ENOSPC error due to
+	 * filesystem is "full" of reservations, but
+	 * there maybe indeed free blocks avaliable on disk
+	 * In this case, we just forget about the reservations
+	 * just do block allocation as without reservations.
+	 */
+	if (my_rsv) {
+		my_rsv = NULL;
+		group_no = goal_group;
+		goto retry;
+	}
 	/* No space left on the device */
 	*errp = -ENOSPC;
 	goto out;
--- diff/fs/ext3/file.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/file.c	2004-05-27 18:34:18.000000000 +0100
@@ -33,8 +33,10 @@
  */
 static int ext3_release_file (struct inode * inode, struct file * filp)
 {
-	if (filp->f_mode & FMODE_WRITE)
-		ext3_discard_prealloc (inode);
+	/* if we are the last writer on the inode, drop the block reservation */
+	if ((filp->f_mode & FMODE_WRITE) &&
+			(atomic_read(&inode->i_writecount) == 1))
+		ext3_discard_reservation(inode);
 	if (is_dx(inode) && filp->private_data)
 		ext3_htree_free_dir_info(filp->private_data);
 
--- diff/fs/ext3/ialloc.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/ialloc.c	2004-05-27 18:34:18.000000000 +0100
@@ -581,10 +581,11 @@
 	ei->i_file_acl = 0;
 	ei->i_dir_acl = 0;
 	ei->i_dtime = 0;
-#ifdef EXT3_PREALLOCATE
-	ei->i_prealloc_block = 0;
-	ei->i_prealloc_count = 0;
-#endif
+	ei->i_rsv_window.rsv_start = 0;
+	ei->i_rsv_window.rsv_end = 0;
+	atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS);
+	ei->i_rsv_window.rsv_alloc_hit = 0;
+	INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list);
 	ei->i_block_group = group;
 
 	ext3_set_inode_flags(inode);
--- diff/fs/ext3/inode.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ext3/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -177,19 +177,6 @@
 }
 
 /*
- * Called at each iput()
- *
- * The inode may be "bad" if ext3_read_inode() saw an error from
- * ext3_get_inode(), so we need to check that to avoid freeing random disk
- * blocks.
- */
-void ext3_put_inode(struct inode *inode)
-{
-	if (!is_bad_inode(inode))
-		ext3_discard_prealloc(inode);
-}
-
-/*
  * Called at the last iput() if i_nlink is zero.
  */
 void ext3_delete_inode (struct inode * inode)
@@ -205,8 +192,6 @@
 		 * need to make sure that the in-core orphan linked list
 		 * is properly cleaned up. */
 		ext3_orphan_del(NULL, inode);
-
-		ext3_std_error(inode->i_sb, PTR_ERR(handle));
 		goto no_delete;
 	}
 
@@ -244,62 +229,12 @@
 	clear_inode(inode);	/* We must guarantee clearing of inode... */
 }
 
-void ext3_discard_prealloc (struct inode * inode)
-{
-#ifdef EXT3_PREALLOCATE
-	struct ext3_inode_info *ei = EXT3_I(inode);
-	/* Writer: ->i_prealloc* */
-	if (ei->i_prealloc_count) {
-		unsigned short total = ei->i_prealloc_count;
-		unsigned long block = ei->i_prealloc_block;
-		ei->i_prealloc_count = 0;
-		ei->i_prealloc_block = 0;
-		/* Writer: end */
-		ext3_free_blocks (inode, block, total);
-	}
-#endif
-}
-
 static int ext3_alloc_block (handle_t *handle,
 			struct inode * inode, unsigned long goal, int *err)
 {
 	unsigned long result;
 
-#ifdef EXT3_PREALLOCATE
-#ifdef EXT3FS_DEBUG
-	static unsigned long alloc_hits, alloc_attempts;
-#endif
-	struct ext3_inode_info *ei = EXT3_I(inode);
-	/* Writer: ->i_prealloc* */
-	if (ei->i_prealloc_count &&
-	    (goal == ei->i_prealloc_block ||
-	     goal + 1 == ei->i_prealloc_block))
-	{
-		result = ei->i_prealloc_block++;
-		ei->i_prealloc_count--;
-		/* Writer: end */
-		ext3_debug ("preallocation hit (%lu/%lu).\n",
-			    ++alloc_hits, ++alloc_attempts);
-	} else {
-		ext3_discard_prealloc (inode);
-		ext3_debug ("preallocation miss (%lu/%lu).\n",
-			    alloc_hits, ++alloc_attempts);
-		if (S_ISREG(inode->i_mode))
-			result = ext3_new_block (inode, goal, 
-				 &ei->i_prealloc_count,
-				 &ei->i_prealloc_block, err);
-		else
-			result = ext3_new_block (inode, goal, 0, 0, err);
-		/*
-		 * AKPM: this is somewhat sticky.  I'm not surprised it was
-		 * disabled in 2.2's ext3.  Need to integrate b_committed_data
-		 * guarding with preallocation, if indeed preallocation is
-		 * effective.
-		 */
-	}
-#else
-	result = ext3_new_block (handle, inode, goal, 0, 0, err);
-#endif
+	result = ext3_new_block (handle, inode, goal, err);
 	return result;
 }
 
@@ -967,38 +902,6 @@
 	bh = ext3_getblk (handle, inode, block, create, err);
 	if (!bh)
 		return bh;
-#ifdef EXT3_PREALLOCATE
-	/*
-	 * If the inode has grown, and this is a directory, then use a few
-	 * more of the preallocated blocks to keep directory fragmentation
-	 * down.  The preallocated blocks are guaranteed to be contiguous.
-	 */
-	if (create &&
-	    S_ISDIR(inode->i_mode) &&
-	    inode->i_blocks > prev_blocks &&
-	    EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
-				    EXT3_FEATURE_COMPAT_DIR_PREALLOC)) {
-		int i;
-		struct buffer_head *tmp_bh;
-
-		for (i = 1;
-		     EXT3_I(inode)->i_prealloc_count &&
-		     i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
-		     i++) {
-			/*
-			 * ext3_getblk will zero out the contents of the
-			 * directory for us
-			 */
-			tmp_bh = ext3_getblk(handle, inode,
-						block+i, create, err);
-			if (!tmp_bh) {
-				brelse (bh);
-				return 0;
-			}
-			brelse (tmp_bh);
-		}
-	}
-#endif
 	if (buffer_uptodate(bh))
 		return bh;
 	ll_rw_block (READ, 1, &bh);
@@ -1082,7 +985,7 @@
 	struct inode *inode = page->mapping->host;
 	int ret, needed_blocks = ext3_writepage_trans_blocks(inode);
 	handle_t *handle;
-	int tried_commit = 0;
+	int retries = 0;
 
 retry:
 	handle = ext3_journal_start(inode, needed_blocks);
@@ -1091,19 +994,8 @@
 		goto out;
 	}
 	ret = block_prepare_write(page, from, to, ext3_get_block);
-	if (ret) {
-		if (ret != -ENOSPC || tried_commit)
-			goto prepare_write_failed;
-		/*
-		 * It could be that there _is_ free space, but it's all tied up
-		 * in uncommitted bitmaps.  So force a commit here, which makes
-		 * those blocks allocatable and try again.
-		 */
-		tried_commit = 1;
-		handle->h_sync = 1;
-		ext3_journal_stop(handle);
-		goto retry;
-	}
+	if (ret)
+		goto prepare_write_failed;
 
 	if (ext3_should_journal_data(inode)) {
 		ret = walk_page_buffers(handle, page_buffers(page),
@@ -1112,6 +1004,8 @@
 prepare_write_failed:
 	if (ret)
 		ext3_journal_stop(handle);
+	if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
+		goto retry;
 out:
 	return ret;
 }
@@ -2150,7 +2044,7 @@
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 		return;
 
-	ext3_discard_prealloc(inode);
+	ext3_discard_reservation(inode);
 
 	/*
 	 * We have to lock the EOF page here, because lock_page() nests
@@ -2543,11 +2437,11 @@
 	}
 	ei->i_disksize = inode->i_size;
 	inode->i_generation = le32_to_cpu(raw_inode->i_generation);
-#ifdef EXT3_PREALLOCATE
-	ei->i_prealloc_count = 0;
-#endif
 	ei->i_block_group = iloc.block_group;
-
+	ei->i_rsv_window.rsv_start = 0;
+	ei->i_rsv_window.rsv_end= 0;
+	atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS);
+	INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list);
 	/*
 	 * NOTE! The in-memory inode i_data array is in little-endian order
 	 * even on big-endian machines: we do NOT byteswap the block numbers!
--- diff/fs/ext3/ioctl.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/ioctl.c	2004-05-27 18:34:18.000000000 +0100
@@ -20,6 +20,7 @@
 {
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	unsigned int flags;
+	unsigned short rsv_window_size;
 
 	ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
 
@@ -151,6 +152,29 @@
 			return ret;
 		}
 #endif
+	case EXT3_IOC_GETRSVSZ:
+		if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode)) {
+			rsv_window_size = atomic_read(&ei->i_rsv_window.rsv_goal_size);
+			return put_user(rsv_window_size, (int *)arg);
+		}
+		return -ENOTTY;
+	case EXT3_IOC_SETRSVSZ:
+		if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
+			return -ENOTTY;
+
+		if (IS_RDONLY(inode))
+			return -EROFS;
+
+		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+			return -EACCES;
+
+		if (get_user(rsv_window_size, (int *)arg))
+			return -EFAULT;
+
+		if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS)
+			rsv_window_size = EXT3_MAX_RESERVE_BLOCKS;
+		atomic_set(&ei->i_rsv_window.rsv_goal_size, rsv_window_size);
+		return 0;
 	default:
 		return -ENOTTY;
 	}
--- diff/fs/ext3/namei.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ext3/namei.c	2004-05-27 18:34:18.000000000 +0100
@@ -1630,8 +1630,9 @@
 {
 	handle_t *handle; 
 	struct inode * inode;
-	int err;
+	int err, retries = 0;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
 					2*EXT3_QUOTA_INIT_BLOCKS);
@@ -1650,6 +1651,8 @@
 		err = ext3_add_nondir(handle, dentry, inode);
 	}
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -1658,11 +1661,12 @@
 {
 	handle_t *handle;
 	struct inode *inode;
-	int err;
+	int err, retries = 0;
 
 	if (!new_valid_dev(rdev))
 		return -EINVAL;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
 					2*EXT3_QUOTA_INIT_BLOCKS);
@@ -1682,6 +1686,8 @@
 		err = ext3_add_nondir(handle, dentry, inode);
 	}
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -1691,11 +1697,12 @@
 	struct inode * inode;
 	struct buffer_head * dir_block;
 	struct ext3_dir_entry_2 * de;
-	int err;
+	int err, retries = 0;
 
 	if (dir->i_nlink >= EXT3_LINK_MAX)
 		return -EMLINK;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
 					2*EXT3_QUOTA_INIT_BLOCKS);
@@ -1753,6 +1760,8 @@
 	d_instantiate(dentry, inode);
 out_stop:
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -2094,12 +2103,13 @@
 {
 	handle_t *handle;
 	struct inode * inode;
-	int l, err;
+	int l, err, retries = 0;
 
 	l = strlen(symname)+1;
 	if (l > dir->i_sb->s_blocksize)
 		return -ENAMETOOLONG;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
 					2*EXT3_QUOTA_INIT_BLOCKS);
@@ -2138,6 +2148,8 @@
 	err = ext3_add_nondir(handle, dentry, inode);
 out_stop:
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -2146,11 +2158,12 @@
 {
 	handle_t *handle;
 	struct inode *inode = old_dentry->d_inode;
-	int err;
+	int err, retries = 0;
 
 	if (inode->i_nlink >= EXT3_LINK_MAX)
 		return -EMLINK;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 					EXT3_INDEX_EXTRA_TRANS_BLOCKS);
 	if (IS_ERR(handle))
@@ -2165,6 +2178,8 @@
 
 	err = ext3_add_nondir(handle, dentry, inode);
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -2264,11 +2279,15 @@
 	/*
 	 * ok, that's it
 	 */
-	retval = ext3_delete_entry(handle, old_dir, old_de, old_bh);
-	if (retval == -ENOENT) {
-		/*
-		 * old_de could have moved out from under us.
-		 */
+	if (le32_to_cpu(old_de->inode) != old_inode->i_ino ||
+	    old_de->name_len != old_dentry->d_name.len ||
+	    strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) ||
+	    (retval = ext3_delete_entry(handle, old_dir,
+					old_de, old_bh)) == -ENOENT) {
+		/* old_de could have moved from under us during htree split, so
+		 * make sure that we are deleting the right entry.  We might
+		 * also be pointing to a stale entry in the unused part of
+		 * old_bh so just checking inum and the name isn't enough. */
 		struct buffer_head *old_bh2;
 		struct ext3_dir_entry_2 *old_de2;
 
--- diff/fs/ext3/super.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ext3/super.c	2004-05-27 18:34:18.000000000 +0100
@@ -493,10 +493,9 @@
 		printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
 }
 
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-
 static void ext3_clear_inode(struct inode *inode)
 {
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
        if (EXT3_I(inode)->i_acl &&
            EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
                posix_acl_release(EXT3_I(inode)->i_acl);
@@ -507,11 +506,10 @@
                posix_acl_release(EXT3_I(inode)->i_default_acl);
                EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
        }
-}
-
-#else
-# define ext3_clear_inode NULL
 #endif
+	if (!is_bad_inode(inode))
+		ext3_discard_reservation(inode);
+}
 
 #ifdef CONFIG_QUOTA
 
@@ -561,7 +559,6 @@
 	.read_inode	= ext3_read_inode,
 	.write_inode	= ext3_write_inode,
 	.dirty_inode	= ext3_dirty_inode,
-	.put_inode	= ext3_put_inode,
 	.delete_inode	= ext3_delete_inode,
 	.put_super	= ext3_put_super,
 	.write_super	= ext3_write_super,
@@ -582,12 +579,13 @@
 	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
 	Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
-	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload,
+	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+	Opt_reservation, Opt_noreservation, Opt_noload,
 	Opt_commit, Opt_journal_update, Opt_journal_inum,
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
-	Opt_ignore, Opt_err,
+	Opt_ignore, Opt_barrier, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -614,6 +612,8 @@
 	{Opt_nouser_xattr, "nouser_xattr"},
 	{Opt_acl, "acl"},
 	{Opt_noacl, "noacl"},
+	{Opt_reservation, "reservation"},
+	{Opt_noreservation, "noreservation"},
 	{Opt_noload, "noload"},
 	{Opt_commit, "commit=%u"},
 	{Opt_journal_update, "journal=update"},
@@ -632,6 +632,7 @@
 	{Opt_ignore, "noquota"},
 	{Opt_ignore, "quota"},
 	{Opt_ignore, "usrquota"},
+	{Opt_barrier, "barrier=%u"},
 	{Opt_err, NULL}
 };
 
@@ -767,6 +768,12 @@
 			printk("EXT3 (no)acl options not supported\n");
 			break;
 #endif
+		case Opt_reservation:
+			set_opt(sbi->s_mount_opt, RESERVATION);
+			break;
+		case Opt_noreservation:
+			clear_opt(sbi->s_mount_opt, RESERVATION);
+			break;
 		case Opt_journal_update:
 			/* @@@ FIXME */
 			/* Eventually we will want to be able to create
@@ -897,6 +904,14 @@
 		case Opt_abort:
 			set_opt(sbi->s_mount_opt, ABORT);
 			break;
+		case Opt_barrier:
+			if (match_int(&args[0], &option))
+				return 0;
+			if (option)
+				set_opt(sbi->s_mount_opt, BARRIER);
+			else
+				clear_opt(sbi->s_mount_opt, BARRIER);
+			break;
 		case Opt_ignore:
 			break;
 		default:
@@ -1288,6 +1303,8 @@
 	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
 	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
 
+	set_opt(sbi->s_mount_opt, RESERVATION);
+
 	if (!parse_options ((char *) data, sb, &journal_inum, 0))
 		goto failed_mount;
 
@@ -1462,6 +1479,14 @@
 	sbi->s_gdb_count = db_count;
 	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
 	spin_lock_init(&sbi->s_next_gen_lock);
+	/* per fileystem reservation list head & lock */
+	spin_lock_init(&sbi->s_rsv_window_lock);
+	INIT_LIST_HEAD(&sbi->s_rsv_window_head.rsv_list);
+	sbi->s_rsv_window_head.rsv_start = 0;
+	sbi->s_rsv_window_head.rsv_end = 0;
+	sbi->s_rsv_window_head.rsv_alloc_hit = 0;
+	atomic_set(&sbi->s_rsv_window_head.rsv_goal_size, 0);
+
 	/*
 	 * set up enough so that it can read an inode
 	 */
@@ -1599,16 +1624,23 @@
  * initial mount, once the journal has been initialised but before we've
  * done any recovery; and again on any subsequent remount. 
  */
-static void ext3_init_journal_params(struct ext3_sb_info *sbi, 
-				     journal_t *journal)
+static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
 {
+	struct ext3_sb_info *sbi = EXT3_SB(sb);
+
 	if (sbi->s_commit_interval)
 		journal->j_commit_interval = sbi->s_commit_interval;
 	/* We could also set up an ext3-specific default for the commit
 	 * interval here, but for now we'll just fall back to the jbd
 	 * default. */
-}
 
+	spin_lock(&journal->j_state_lock);
+	if (test_opt(sb, BARRIER))
+		journal->j_flags |= JFS_BARRIER;
+	else
+		journal->j_flags &= ~JFS_BARRIER;
+	spin_unlock(&journal->j_state_lock);
+}
 
 static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
 {
@@ -1645,7 +1677,7 @@
 		iput(journal_inode);
 	}
 	journal->j_private = sb;
-	ext3_init_journal_params(EXT3_SB(sb), journal);
+	ext3_init_journal_params(sb, journal);
 	return journal;
 }
 
@@ -1730,7 +1762,7 @@
 		goto out_journal;
 	}
 	EXT3_SB(sb)->journal_bdev = bdev;
-	ext3_init_journal_params(EXT3_SB(sb), journal);
+	ext3_init_journal_params(sb, journal);
 	return journal;
 out_journal:
 	journal_destroy(journal);
@@ -2023,7 +2055,7 @@
 
 	es = sbi->s_es;
 
-	ext3_init_journal_params(sbi, sbi->s_journal);
+	ext3_init_journal_params(sb, sbi->s_journal);
 
 	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
 		if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
--- diff/fs/ext3/symlink.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -22,22 +22,17 @@
 #include <linux/ext3_fs.h>
 #include "xattr.h"
 
-static int
-ext3_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
-	return vfs_readlink(dentry, buffer, buflen, (char*)ei->i_data);
-}
-
 static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
-	return vfs_follow_link(nd, (char*)ei->i_data);
+	nd_set_link(nd, (char*)ei->i_data);
+	return 0;
 }
 
 struct inode_operations ext3_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.setxattr	= ext3_setxattr,
 	.getxattr	= ext3_getxattr,
 	.listxattr	= ext3_listxattr,
@@ -45,8 +40,8 @@
 };
 
 struct inode_operations ext3_fast_symlink_inode_operations = {
-	.readlink	= ext3_readlink,	/* BKL not held.  Don't need */
-	.follow_link	= ext3_follow_link,	/* BKL not held.  Don't need */
+	.readlink	= generic_readlink,
+	.follow_link	= ext3_follow_link,
 	.setxattr	= ext3_setxattr,
 	.getxattr	= ext3_getxattr,
 	.listxattr	= ext3_listxattr,
--- diff/fs/ext3/xattr.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/xattr.c	2004-05-27 18:34:18.000000000 +0100
@@ -787,7 +787,7 @@
 				EXT3_I(inode)->i_block_group *
 				EXT3_BLOCKS_PER_GROUP(sb);
 			int block = ext3_new_block(handle,
-				inode, goal, 0, 0, &error);
+				inode, goal, &error);
 			if (error)
 				goto cleanup;
 			ea_idebug(inode, "creating block %d", block);
@@ -875,8 +875,9 @@
 	       const void *value, size_t value_len, int flags)
 {
 	handle_t *handle;
-	int error;
+	int error, retries = 0;
 
+retry:
 	handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
 	if (IS_ERR(handle)) {
 		error = PTR_ERR(handle);
@@ -886,6 +887,9 @@
 		error = ext3_xattr_set_handle(handle, inode, name_index, name,
 					      value, value_len, flags);
 		error2 = ext3_journal_stop(handle);
+		if (error == -ENOSPC &&
+		    ext3_should_retry_alloc(inode->i_sb, &retries))
+			goto retry;
 		if (error == 0)
 			error = error2;
 	}
--- diff/fs/fat/file.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/fat/file.c	2004-05-27 18:34:18.000000000 +0100
@@ -47,7 +47,8 @@
 	if (!create)
 		return 0;
 	if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
-		BUG();
+		fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",
+			     MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
 		return -EIO;
 	}
 	if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) {
--- diff/fs/fat/inode.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/fat/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -1245,7 +1245,7 @@
 	lock_kernel();
 	if (!(bh = sb_bread(sb, i_pos >> MSDOS_SB(sb)->dir_per_block_bits))) {
 		printk(KERN_ERR "FAT: unable to read inode block "
-		       "for updating (i_pos %lld)", i_pos);
+		       "for updating (i_pos %lld)\n", i_pos);
 		unlock_kernel();
 		return /* -EIO */;
 	}
--- diff/fs/freevxfs/vxfs_immed.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/freevxfs/vxfs_immed.c	2004-05-27 18:34:18.000000000 +0100
@@ -37,7 +37,6 @@
 #include "vxfs_inode.h"
 
 
-static int	vxfs_immed_readlink(struct dentry *, char __user *, int);
 static int	vxfs_immed_follow_link(struct dentry *, struct nameidata *);
 
 static int	vxfs_immed_readpage(struct file *, struct page *);
@@ -49,7 +48,7 @@
  * but do all work directly on the inode.
  */
 struct inode_operations vxfs_immed_symlink_iops = {
-	.readlink =		vxfs_immed_readlink,
+	.readlink =		generic_readlink,
 	.follow_link =		vxfs_immed_follow_link,
 };
 
@@ -60,28 +59,6 @@
 	.readpage =		vxfs_immed_readpage,
 };
 
-
-/**
- * vxfs_immed_readlink - read immed symlink
- * @dp:		dentry for the link
- * @bp:		output buffer
- * @buflen:	length of @bp
- *
- * Description:
- *   vxfs_immed_readlink calls vfs_readlink to read the link
- *   described by @dp into userspace.
- *
- * Returns:
- *   Number of bytes successfully copied to userspace.
- */
-static int
-vxfs_immed_readlink(struct dentry *dp, char __user *bp, int buflen)
-{
-	struct vxfs_inode_info		*vip = VXFS_INO(dp->d_inode);
-
-	return (vfs_readlink(dp, bp, buflen, vip->vii_immed.vi_immed));
-}
-
 /**
  * vxfs_immed_follow_link - follow immed symlink
  * @dp:		dentry for the link
@@ -98,8 +75,8 @@
 vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np)
 {
 	struct vxfs_inode_info		*vip = VXFS_INO(dp->d_inode);
-
-	return (vfs_follow_link(np, vip->vii_immed.vi_immed));
+	nd_set_link(np, vip->vii_immed.vi_immed);
+	return 0;
 }
 
 /**
--- diff/fs/fs-writeback.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/fs-writeback.c	2004-05-27 18:34:18.000000000 +0100
@@ -425,10 +425,7 @@
 {
 	struct page_state ps;
 	struct writeback_control wbc = {
-		.bdi		= NULL,
 		.sync_mode	= wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
-		.older_than_this = NULL,
-		.nr_to_write	= 0,
 	};
 
 	get_page_state(&ps);
@@ -439,6 +436,9 @@
 	spin_lock(&inode_lock);
 	sync_sb_inodes(sb, &wbc);
 	spin_unlock(&inode_lock);
+	if (wbc.nr_to_write <= 0)
+		printk(KERN_ERR "%s: not all pages were written!\n",
+				__FUNCTION__);
 }
 
 /*
--- diff/fs/hfs/catalog.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/hfs/catalog.c	2004-05-27 18:34:18.000000000 +0100
@@ -101,11 +101,11 @@
 	if (err != -ENOENT) {
 		if (!err)
 			err = -EEXIST;
-		goto out;
+		goto err2;
 	}
 	err = hfs_brec_insert(&fd, &entry, entry_size);
 	if (err)
-		goto out;
+		goto err2;
 
 	hfs_cat_build_key(fd.search_key, dir->i_ino, str);
 	entry_size = hfs_cat_build_record(&entry, cnid, inode);
@@ -114,16 +114,24 @@
 		/* panic? */
 		if (!err)
 			err = -EEXIST;
-		goto out;
+		goto err1;
 	}
 	err = hfs_brec_insert(&fd, &entry, entry_size);
-	if (!err) {
-		dir->i_size++;
-		mark_inode_dirty(dir);
-	}
-out:
+	if (err)
+		goto err1;
+
+	dir->i_size++;
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(dir);
 	hfs_find_exit(&fd);
+	return 0;
 
+err1:
+	hfs_cat_build_key(fd.search_key, cnid, NULL);
+	if (!hfs_brec_find(&fd))
+		hfs_brec_remove(&fd);
+err2:
+	hfs_find_exit(&fd);
 	return err;
 }
 
@@ -240,6 +248,7 @@
 	}
 
 	dir->i_size--;
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
 	res = 0;
 out:
@@ -292,6 +301,7 @@
 	if (err)
 		goto out;
 	dst_dir->i_size++;
+	dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dst_dir);
 
 	/* finally remove the old entry */
@@ -303,6 +313,7 @@
 	if (err)
 		goto out;
 	src_dir->i_size--;
+	src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(src_dir);
 
 	type = entry.type;
--- diff/fs/hfs/inode.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/hfs/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -96,7 +96,7 @@
 			}
 			hfs_bnode_unhash(node);
 			hfs_bnode_free(node);
-		} while (--i);
+		} while (--i && nidx < tree->node_count);
 		spin_unlock(&tree->hash_lock);
 	}
 	//printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
--- diff/fs/hfsplus/brec.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/hfsplus/brec.c	2004-05-27 18:34:18.000000000 +0100
@@ -33,7 +33,7 @@
 
 	if ((node->type == HFS_NODE_INDEX) &&
 	   !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
-		retval = node->tree->max_key_len;
+		retval = node->tree->max_key_len + 2;
 	} else {
 		recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
 		if (!recoff)
@@ -144,7 +144,7 @@
 		if (tree->attributes & HFS_TREE_VARIDXKEYS)
 			key_len = be16_to_cpu(fd->search_key->key_len) + 2;
 		else {
-			fd->search_key->key_len = tree->max_key_len;
+			fd->search_key->key_len = cpu_to_be16(tree->max_key_len);
 			key_len = tree->max_key_len + 2;
 		}
 		goto again;
--- diff/fs/hfsplus/catalog.c	2004-05-19 22:12:27.000000000 +0100
+++ source/fs/hfsplus/catalog.c	2004-05-27 18:34:18.000000000 +0100
@@ -165,11 +165,11 @@
 	if (err != -ENOENT) {
 		if (!err)
 			err = -EEXIST;
-		goto out;
+		goto err2;
 	}
 	err = hfs_brec_insert(&fd, &entry, entry_size);
 	if (err)
-		goto out;
+		goto err2;
 
 	hfsplus_cat_build_key(fd.search_key, dir->i_ino, str);
 	entry_size = hfsplus_cat_build_record(&entry, cnid, inode);
@@ -178,16 +178,24 @@
 		/* panic? */
 		if (!err)
 			err = -EEXIST;
-		goto out;
+		goto err1;
 	}
 	err = hfs_brec_insert(&fd, &entry, entry_size);
-	if (!err) {
-		dir->i_size++;
-		mark_inode_dirty(dir);
-	}
-out:
+	if (err)
+		goto err1;
+
+	dir->i_size++;
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(dir);
 	hfs_find_exit(&fd);
+	return 0;
 
+err1:
+	hfsplus_cat_build_key(fd.search_key, cnid, NULL);
+	if (!hfs_brec_find(&fd))
+		hfs_brec_remove(&fd);
+err2:
+	hfs_find_exit(&fd);
 	return err;
 }
 
@@ -259,6 +267,7 @@
 		goto out;
 
 	dir->i_size--;
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
 out:
 	hfs_find_exit(&fd);
@@ -304,6 +313,7 @@
 	if (err)
 		goto out;
 	dst_dir->i_size++;
+	dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dst_dir);
 
 	/* finally remove the old entry */
@@ -315,6 +325,7 @@
 	if (err)
 		goto out;
 	src_dir->i_size--;
+	src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(src_dir);
 
 	/* remove old thread entry */
--- diff/fs/hfsplus/dir.c	2004-05-19 22:12:27.000000000 +0100
+++ source/fs/hfsplus/dir.c	2004-05-27 18:34:18.000000000 +0100
@@ -18,6 +18,13 @@
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
 
+static inline void hfsplus_instantiate(struct dentry *dentry,
+				       struct inode *inode, u32 cnid)
+{
+	dentry->d_fsdata = (void *)(unsigned long)cnid;
+	d_instantiate(dentry, inode);
+}
+
 /* Find the entry inside dir named dentry->d_name */
 static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
 				     struct nameidata *nd)
@@ -52,6 +59,7 @@
 			goto fail;
 		}
 		cnid = be32_to_cpu(entry.folder.id);
+		dentry->d_fsdata = (void *)(unsigned long)cnid;
 	} else if (type == HFSPLUS_FILE) {
 		if (fd.entrylength < sizeof(struct hfsplus_cat_file)) {
 			err = -EIO;
@@ -233,11 +241,11 @@
 	res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
 	if (res) {
 		inode->i_nlink = 0;
+		hfsplus_delete_inode(inode);
 		iput(inode);
 		return res;
 	}
-	dentry->d_fsdata = (void *)inode->i_ino;
-	d_instantiate(dentry, inode);
+	hfsplus_instantiate(dentry, inode, inode->i_ino);
 	mark_inode_dirty(inode);
 	return 0;
 }
@@ -284,8 +292,7 @@
 		return res;
 
 	inode->i_nlink++;
-	dst_dentry->d_fsdata = (void *)(unsigned long)cnid;
-	d_instantiate(dst_dentry, inode);
+	hfsplus_instantiate(dst_dentry, inode, cnid);
 	atomic_inc(&inode->i_count);
 	inode->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(inode);
@@ -351,10 +358,11 @@
 	res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
 	if (res) {
 		inode->i_nlink = 0;
+		hfsplus_delete_inode(inode);
 		iput(inode);
 		return res;
 	}
-	d_instantiate(dentry, inode);
+	hfsplus_instantiate(dentry, inode, inode->i_ino);
 	mark_inode_dirty(inode);
 	return 0;
 }
@@ -391,7 +399,8 @@
 	res = page_symlink(inode, symname, strlen(symname) + 1);
 	if (res) {
 		inode->i_nlink = 0;
-		iput (inode);
+		hfsplus_delete_inode(inode);
+		iput(inode);
 		return res;
 	}
 
@@ -399,8 +408,7 @@
 	res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
 
 	if (!res) {
-		dentry->d_fsdata = (void *)inode->i_ino;
-		d_instantiate(dentry, inode);
+		hfsplus_instantiate(dentry, inode, inode->i_ino);
 		mark_inode_dirty(inode);
 	}
 
@@ -421,12 +429,12 @@
 	res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
 	if (res) {
 		inode->i_nlink = 0;
+		hfsplus_delete_inode(inode);
 		iput(inode);
 		return res;
 	}
 	init_special_inode(inode, mode, rdev);
-	dentry->d_fsdata = (void *)inode->i_ino;
-	d_instantiate(dentry, inode);
+	hfsplus_instantiate(dentry, inode, inode->i_ino);
 	mark_inode_dirty(inode);
 
 	return 0;
--- diff/fs/hfsplus/inode.c	2004-05-19 22:12:27.000000000 +0100
+++ source/fs/hfsplus/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -96,7 +96,7 @@
 			}
 			hfs_bnode_unhash(node);
 			hfs_bnode_free(node);
-		} while (--i);
+		} while (--i && nidx < tree->node_count);
 		spin_unlock(&tree->hash_lock);
 	}
 	//printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
--- diff/fs/hugetlbfs/inode.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/hugetlbfs/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -196,6 +196,7 @@
 
 	hlist_del_init(&inode->i_hash);
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state |= I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -238,6 +239,7 @@
 	hlist_del_init(&inode->i_hash);
 out_truncate:
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state |= I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -720,8 +722,11 @@
 
 static int can_do_hugetlb_shm(void)
 {
-	return likely(capable(CAP_IPC_LOCK) ||
-			in_group_p(sysctl_hugetlb_shm_group));
+	if (capable(CAP_IPC_LOCK))
+		return 1;
+	if (sysctl_hugetlb_shm_group == 0)
+		return 0;
+	return in_group_p(sysctl_hugetlb_shm_group);
 }
 
 struct file *hugetlb_zero_setup(size_t size)
--- diff/fs/inode.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -195,7 +195,7 @@
 	sema_init(&inode->i_sem, 1);
 	init_rwsem(&inode->i_alloc_sem);
 	INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
-	spin_lock_init(&inode->i_data.tree_lock);
+	rwlock_init(&inode->i_data.tree_lock);
 	spin_lock_init(&inode->i_data.i_mmap_lock);
 	atomic_set(&inode->i_data.truncate_count, 0);
 	INIT_LIST_HEAD(&inode->i_data.private_list);
@@ -294,7 +294,7 @@
 /*
  * Invalidate all inodes for a device.
  */
-static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose)
+static int invalidate_list(struct list_head *head, struct list_head *dispose)
 {
 	struct list_head *next;
 	int busy = 0, count = 0;
@@ -307,12 +307,11 @@
 		next = next->next;
 		if (tmp == head)
 			break;
-		inode = list_entry(tmp, struct inode, i_list);
-		if (inode->i_sb != sb)
-			continue;
+		inode = list_entry(tmp, struct inode, i_sb_list);
 		invalidate_inode_buffers(inode);
 		if (!atomic_read(&inode->i_count)) {
 			hlist_del_init(&inode->i_hash);
+			list_del(&inode->i_sb_list);
 			list_move(&inode->i_list, dispose);
 			inode->i_state |= I_FREEING;
 			count++;
@@ -348,10 +347,7 @@
 
 	down(&iprune_sem);
 	spin_lock(&inode_lock);
-	busy = invalidate_list(&inode_in_use, sb, &throw_away);
-	busy |= invalidate_list(&inode_unused, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_io, sb, &throw_away);
+	busy = invalidate_list(&sb->s_inodes, &throw_away);
 	spin_unlock(&inode_lock);
 
 	dispose_list(&throw_away);
@@ -451,6 +447,7 @@
 				continue;
 		}
 		hlist_del_init(&inode->i_hash);
+		list_del_init(&inode->i_sb_list);
 		list_move(&inode->i_list, &freeable);
 		inode->i_state |= I_FREEING;
 		nr_pruned++;
@@ -561,6 +558,7 @@
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
+		list_add(&inode->i_sb_list, &sb->s_inodes);
 		inode->i_ino = ++last_ino;
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
@@ -609,6 +607,7 @@
 
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_sb_list, &sb->s_inodes);
 			hlist_add_head(&inode->i_hash, head);
 			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
@@ -657,6 +656,7 @@
 			inode->i_ino = ino;
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_sb_list, &sb->s_inodes);
 			hlist_add_head(&inode->i_hash, head);
 			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
@@ -993,6 +993,7 @@
 	struct super_operations *op = inode->i_sb->s_op;
 
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state|=I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -1038,6 +1039,7 @@
 		hlist_del_init(&inode->i_hash);
 	}
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state|=I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -1226,36 +1228,23 @@
 /* Function back in dquot.c */
 int remove_inode_dquot_ref(struct inode *, int, struct list_head *);
 
-void remove_dquot_ref(struct super_block *sb, int type, struct list_head *tofree_head)
+void remove_dquot_ref(struct super_block *sb, int type,
+			struct list_head *tofree_head)
 {
 	struct inode *inode;
-	struct list_head *act_head;
 
 	if (!sb->dq_op)
 		return;	/* nothing to do */
 	spin_lock(&inode_lock);	/* This lock is for inodes code */
-	/* We don't have to lock against quota code - test IS_QUOTAINIT is just for speedup... */
- 
-	list_for_each(act_head, &inode_in_use) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, tofree_head);
-	}
-	list_for_each(act_head, &inode_unused) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, tofree_head);
-	}
-	list_for_each(act_head, &sb->s_dirty) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, tofree_head);
-	}
-	list_for_each(act_head, &sb->s_io) {
-		inode = list_entry(act_head, struct inode, i_list);
+	/*
+	 * We don't have to lock against quota code - test IS_QUOTAINIT is
+	 * just for speedup...
+	 */
+
+	list_for_each_entry(inode, &sb->s_inodes, i_sb_list)
 		if (IS_QUOTAINIT(inode))
 			remove_inode_dquot_ref(inode, type, tofree_head);
-	}
+
 	spin_unlock(&inode_lock);
 }
 
--- diff/fs/isofs/inode.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/isofs/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -1207,7 +1207,7 @@
 	struct iso_directory_record * tmpde = NULL;
 	unsigned int de_len;
 	unsigned long offset;
-	int volume_seq_no, i;
+	int i;
 	struct iso_inode_info *ei = ISOFS_I(inode);
 
 	bh = sb_bread(inode->i_sb, block);
@@ -1348,9 +1348,6 @@
 		test_and_set_gid(&inode->i_gid, sbi->s_gid);
 	}
 
-	/* get the volume sequence number */
-	volume_seq_no = isonum_723 (de->volume_sequence_number) ;
-
 	/* Install the inode operations vector */
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_fop = &generic_ro_fops;
--- diff/fs/jbd/commit.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/jbd/commit.c	2004-05-27 18:34:18.000000000 +0100
@@ -638,9 +638,29 @@
 	JBUFFER_TRACE(descriptor, "write commit block");
 	{
 		struct buffer_head *bh = jh2bh(descriptor);
+		int ret;
+
 		set_buffer_uptodate(bh);
-		sync_dirty_buffer(bh);
-		if (unlikely(!buffer_uptodate(bh)))
+		if (journal->j_flags & JFS_BARRIER)
+			set_buffer_ordered(bh);
+		ret = sync_dirty_buffer(bh);
+		if (ret == -EOPNOTSUPP && (journal->j_flags & JFS_BARRIER)) {
+			char b[BDEVNAME_SIZE];
+
+			printk(KERN_WARNING
+				"JBD: barrier-based sync failed on %s - "
+				"disabling barriers\n",
+				bdevname(journal->j_dev, b));
+			spin_lock(&journal->j_state_lock);
+			journal->j_flags &= ~JFS_BARRIER;
+			spin_unlock(&journal->j_state_lock);
+
+			/* And try again, without the barrier */
+			clear_buffer_ordered(bh);
+			set_buffer_dirty(bh);
+			ret = sync_dirty_buffer(bh);
+		}
+		if (unlikely(ret == -EIO))
 			err = -EIO;
 		put_bh(bh);		/* One for getblk() */
 		journal_put_journal_head(descriptor);
--- diff/fs/jbd/journal.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/jbd/journal.c	2004-05-27 18:34:18.000000000 +0100
@@ -73,6 +73,7 @@
 EXPORT_SYMBOL(journal_clear_err);
 EXPORT_SYMBOL(log_wait_commit);
 EXPORT_SYMBOL(journal_start_commit);
+EXPORT_SYMBOL(journal_force_commit_nested);
 EXPORT_SYMBOL(journal_wipe);
 EXPORT_SYMBOL(journal_blocks_per_page);
 EXPORT_SYMBOL(journal_invalidatepage);
@@ -465,6 +466,39 @@
 }
 
 /*
+ * Force and wait upon a commit if the calling process is not within
+ * transaction.  This is used for forcing out undo-protected data which contains
+ * bitmaps, when the fs is running out of space.
+ *
+ * We can only force the running transaction if we don't have an active handle;
+ * otherwise, we will deadlock.
+ *
+ * Returns true if a transaction was started.
+ */
+int journal_force_commit_nested(journal_t *journal)
+{
+	transaction_t *transaction = NULL;
+	tid_t tid;
+
+	spin_lock(&journal->j_state_lock);
+	if (journal->j_running_transaction && !current->journal_info) {
+		transaction = journal->j_running_transaction;
+		__log_start_commit(journal, transaction->t_tid);
+	} else if (journal->j_committing_transaction)
+		transaction = journal->j_committing_transaction;
+
+	if (!transaction) {
+		spin_unlock(&journal->j_state_lock);
+		return 0;	/* Nothing to retry */
+	}
+
+	tid = transaction->t_tid;
+	spin_unlock(&journal->j_state_lock);
+	log_wait_commit(journal, tid);
+	return 1;
+}
+
+/*
  * Start a commit of the current running transaction (if any).  Returns true
  * if a transaction was started, and fills its tid in at *ptid
  */
@@ -1674,9 +1708,17 @@
 	if (buffer_jbd(bh)) {
 		jh = bh2jh(bh);
 	} else {
-		J_ASSERT_BH(bh,
-			(atomic_read(&bh->b_count) > 0) ||
-			(bh->b_page && bh->b_page->mapping));
+		if (!(atomic_read(&bh->b_count) > 0 ||
+				(bh->b_page && bh->b_page->mapping))) {
+			printk(KERN_EMERG "%s: bh->b_count=%d\n",
+				__FUNCTION__, atomic_read(&bh->b_count));
+			printk(KERN_EMERG "%s: bh->b_page=%p\n",
+				__FUNCTION__, bh->b_page);
+			if (bh->b_page)
+				printk(KERN_EMERG "%s: "
+						"bh->b_page->mapping=%p\n",
+					__FUNCTION__, bh->b_page->mapping);
+		}
 
 		if (!new_jh) {
 			jbd_unlock_bh_journal_head(bh);
--- diff/fs/jbd/transaction.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/jbd/transaction.c	2004-05-27 18:34:18.000000000 +0100
@@ -939,7 +939,6 @@
 int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
 {
 	journal_t *journal = handle->h_transaction->t_journal;
-	int need_brelse = 0;
 	struct journal_head *jh;
 
 	if (is_handle_aborted(handle))
@@ -1024,24 +1023,6 @@
 				goto no_journal;
 			}
 
-			/*
-			 * This buffer may be undergoing writeout in commit.  We
-			 * can't return from here and let the caller dirty it
-			 * again because that can cause the write-out loop in
-			 * commit to never terminate.
-			 */
-			if (buffer_dirty(bh)) {
-				get_bh(bh);
-				spin_unlock(&journal->j_list_lock);
-				jbd_unlock_bh_state(bh);
-				need_brelse = 1;
-				sync_dirty_buffer(bh);
-				jbd_lock_bh_state(bh);
-				spin_lock(&journal->j_list_lock);
-				/* The buffer may become locked again at any
-				   time if it is redirtied */
-			}
-
 			/* journal_clean_data_list() may have got there first */
 			if (jh->b_transaction != NULL) {
 				JBUFFER_TRACE(jh, "unfile from commit");
@@ -1071,10 +1052,6 @@
 no_journal:
 	spin_unlock(&journal->j_list_lock);
 	jbd_unlock_bh_state(bh);
-	if (need_brelse) {
-		BUFFER_TRACE(bh, "brelse");
-		__brelse(bh);
-	}
 	JBUFFER_TRACE(jh, "exit");
 	journal_put_journal_head(jh);
 	return 0;
--- diff/fs/jffs2/symlink.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/jffs2/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -17,41 +17,28 @@
 #include <linux/fs.h>
 #include "nodelist.h"
 
-int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen);
-int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
+static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
+static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd);
 
 struct inode_operations jffs2_symlink_inode_operations =
 {	
-	.readlink =	jffs2_readlink,
+	.readlink =	generic_readlink,
 	.follow_link =	jffs2_follow_link,
+	.put_link =	jffs2_put_link,
 	.setattr =	jffs2_setattr
 };
 
-int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	unsigned char *kbuf;
-	int ret;
-
-	kbuf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
-	if (IS_ERR(kbuf))
-		return PTR_ERR(kbuf);
-
-	ret = vfs_readlink(dentry, buffer, buflen, kbuf);
-	kfree(kbuf);
-	return ret;
-}
-
-int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
+static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	unsigned char *buf;
-	int ret;
-
 	buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
+	nd_set_link(nd, buf);
+	return 0;
+}
 
-	if (IS_ERR(buf))
-		return PTR_ERR(buf);
-
-	ret = vfs_follow_link(nd, buf);
-	kfree(buf);
-	return ret;
+static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *s = nd_get_link(nd);
+	if (!IS_ERR(s))
+		kfree(s);
 }
--- diff/fs/jfs/symlink.c	2004-05-19 22:12:29.000000000 +0100
+++ source/fs/jfs/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -23,17 +23,12 @@
 static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	char *s = JFS_IP(dentry->d_inode)->i_inline;
-	return vfs_follow_link(nd, s);
-}
-
-static int jfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	char *s = JFS_IP(dentry->d_inode)->i_inline;
-	return vfs_readlink(dentry, buffer, buflen, s);
+	nd_set_link(nd, s);
+	return 0;
 }
 
 struct inode_operations jfs_symlink_inode_operations = {
-	.readlink	= jfs_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= jfs_follow_link,
 	.setxattr	= jfs_setxattr,
 	.getxattr	= jfs_getxattr,
--- diff/fs/locks.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/locks.c	2004-05-27 18:34:18.000000000 +0100
@@ -1720,6 +1720,9 @@
 				lease_modify(before, F_UNLCK);
 				continue;
 			}
+			/* FL_POSIX locks of this process have already been
+			 * removed in filp_close->locks_remove_posix.
+			 */
 			BUG();
  		}
 		before = &fl->fl_next;
@@ -1979,18 +1982,49 @@
 
 EXPORT_SYMBOL(lock_may_write);
 
+static inline void __steal_locks(struct file *file, fl_owner_t from)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct file_lock *fl = inode->i_flock;
+
+	while (fl) {
+		if (fl->fl_file == file && fl->fl_owner == from)
+			fl->fl_owner = current->files;
+		fl = fl->fl_next;
+	}
+}
+
+/* When getting ready for executing a binary, we make sure that current
+ * has a files_struct on its own. Before dropping the old files_struct,
+ * we take over ownership of all locks for all file descriptors we own.
+ * Note that we may accidentally steal a lock for a file that a sibling
+ * has created since the unshare_files() call.
+ */
 void steal_locks(fl_owner_t from)
 {
-	struct list_head *tmp;
+	struct files_struct *files = current->files;
+	int i, j;
 
-	if (from == current->files)
+	if (from == files)
 		return;
 
 	lock_kernel();
-	list_for_each(tmp, &file_lock_list) {
-		struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
-		if (fl->fl_owner == from)
-			fl->fl_owner = current->files;
+	j = 0;
+	for (;;) {
+		unsigned long set;
+		i = j * __NFDBITS;
+		if (i >= files->max_fdset || i >= files->max_fds)
+			break;
+		set = files->open_fds->fds_bits[j++];
+		while (set) {
+			if (set & 1) {
+				struct file *file = files->fd[i];
+				if (file)
+					__steal_locks(file, from);
+			}
+			i++;
+			set >>= 1;
+		}
 	}
 	unlock_kernel();
 }
--- diff/fs/minix/inode.c	2004-05-19 22:12:29.000000000 +0100
+++ source/fs/minix/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -343,8 +343,9 @@
 };
 
 static struct inode_operations minix_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.getattr	= minix_getattr,
 };
 
--- diff/fs/namei.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/namei.c	2004-05-27 18:34:18.000000000 +0100
@@ -395,6 +395,21 @@
 	return result;
 }
 
+inline void nd_set_link(struct nameidata *nd, char *path)
+{
+	nd->saved_names[current->link_count] = path;
+}
+
+inline char *nd_get_link(struct nameidata *nd)
+{
+	return nd->saved_names[current->link_count];
+}
+
+EXPORT_SYMBOL(nd_set_link);
+EXPORT_SYMBOL(nd_get_link);
+
+static inline int __vfs_follow_link(struct nameidata *, const char *);
+
 /*
  * This limits recursive symlink follows to 8, while
  * limiting consecutive symlinks to 40.
@@ -405,7 +420,7 @@
 static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	int err = -ELOOP;
-	if (current->link_count >= 5)
+	if (current->link_count >= MAX_NESTED_LINKS)
 		goto loop;
 	if (current->total_link_count >= 40)
 		goto loop;
@@ -416,7 +431,15 @@
 	current->link_count++;
 	current->total_link_count++;
 	touch_atime(nd->mnt, dentry);
+	nd_set_link(nd, NULL);
 	err = dentry->d_inode->i_op->follow_link(dentry, nd);
+	if (!err) {
+		char *s = nd_get_link(nd);
+		if (s)
+			err = __vfs_follow_link(nd, s);
+		if (dentry->d_inode->i_op->put_link)
+			dentry->d_inode->i_op->put_link(dentry, nd);
+	}
 	current->link_count--;
 	return err;
 loop:
@@ -1380,7 +1403,15 @@
 	if (error)
 		goto exit_dput;
 	touch_atime(nd->mnt, dentry);
+	nd_set_link(nd, NULL);
 	error = dentry->d_inode->i_op->follow_link(dentry, nd);
+	if (!error) {
+		char *s = nd_get_link(nd);
+		if (s)
+			error = __vfs_follow_link(nd, s);
+		if (dentry->d_inode->i_op->put_link)
+			dentry->d_inode->i_op->put_link(dentry, nd);
+	}
 	dput(dentry);
 	if (error)
 		return error;
@@ -2161,6 +2192,23 @@
 	return len;
 }
 
+/*
+ * A helper for ->readlink().  This should be used *ONLY* for symlinks that
+ * have ->follow_link() touching nd only in nd_set_link().  Using (or not
+ * using) it for any given inode is up to filesystem.
+ */
+int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+{
+	struct nameidata nd;
+	int res = dentry->d_inode->i_op->follow_link(dentry, &nd);
+	if (!res) {
+		res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
+		if (dentry->d_inode->i_op->put_link)
+			dentry->d_inode->i_op->put_link(dentry, &nd);
+	}
+	return res;
+}
+
 static inline int
 __vfs_follow_link(struct nameidata *nd, const char *link)
 {
@@ -2237,6 +2285,30 @@
 	return res;
 }
 
+int page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
+{
+	struct page *page;
+	char *s = page_getlink(dentry, &page);
+	if (!IS_ERR(s)) {
+		nd_set_link(nd, s);
+		s = NULL;
+	}
+	return PTR_ERR(s);
+}
+
+void page_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+	if (!IS_ERR(nd_get_link(nd))) {
+		struct page *page;
+		page = find_get_page(dentry->d_inode->i_mapping, 0);
+		if (!page)
+			BUG();
+		kunmap(page);
+		page_cache_release(page);
+		page_cache_release(page);
+	}
+}
+
 int page_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct page *page = NULL;
@@ -2291,8 +2363,9 @@
 }
 
 struct inode_operations page_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 };
 
 EXPORT_SYMBOL(__user_walk);
@@ -2305,6 +2378,8 @@
 EXPORT_SYMBOL(lookup_hash);
 EXPORT_SYMBOL(lookup_one_len);
 EXPORT_SYMBOL(page_follow_link);
+EXPORT_SYMBOL(page_follow_link_light);
+EXPORT_SYMBOL(page_put_link);
 EXPORT_SYMBOL(page_readlink);
 EXPORT_SYMBOL(page_symlink);
 EXPORT_SYMBOL(page_symlink_inode_operations);
@@ -2324,3 +2399,4 @@
 EXPORT_SYMBOL(vfs_rmdir);
 EXPORT_SYMBOL(vfs_symlink);
 EXPORT_SYMBOL(vfs_unlink);
+EXPORT_SYMBOL(generic_readlink);
--- diff/fs/nfsd/nfs4idmap.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/nfsd/nfs4idmap.c	2004-05-27 18:34:18.000000000 +0100
@@ -175,6 +175,14 @@
 	return 0;
 }
 
+static void
+warn_no_idmapd(struct cache_detail *detail)
+{
+	printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n",
+			detail->last_close? "died" : "not been started");
+}
+
+
 static int         idtoname_parse(struct cache_detail *, char *, int);
 static struct ent *idtoname_lookup(struct ent *, int);
 
@@ -186,6 +194,7 @@
 	.cache_request	= idtoname_request,
 	.cache_parse	= idtoname_parse,
 	.cache_show	= idtoname_show,
+	.warn_no_listener = warn_no_idmapd,
 };
 
 int
@@ -318,6 +327,7 @@
 	.cache_request	= nametoid_request,
 	.cache_parse	= nametoid_parse,
 	.cache_show	= nametoid_show,
+	.warn_no_listener = warn_no_idmapd,
 };
 
 int
--- diff/fs/nfsd/vfs.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/nfsd/vfs.c	2004-05-27 18:34:18.000000000 +0100
@@ -1228,8 +1228,8 @@
 		err = nfserrno(err);
 	fh_unlock(fhp);
 
-	/* Compose the fh so the dentry will be freed ... */
 	cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
+	dput(dnew);
 	if (err==0) err = cerr;
 out:
 	return err;
--- diff/fs/ntfs/ChangeLog	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ntfs/ChangeLog	2004-05-27 18:34:18.000000000 +0100
@@ -25,6 +25,18 @@
 	  sufficient for synchronisation here. We then just need to make sure
 	  ntfs_readpage/writepage/truncate interoperate properly with us.
 
+2.1.12 - WIP.
+
+	- Add a new address space operations struct, ntfs_mst_aops, for mst
+	  protected attributes.  This is because the default ntfs_aops do not
+	  make sense with mst protected data and were they to write anything to
+	  such an attribute they would cause data corruption so we provide
+	  ntfs_mst_aops which does not have any write related operations set.
+	- Cleanup dirty ntfs inode handling (fs/ntfs/inode.[hc]) which also
+	  includes an adapted ntfs_commit_inode() and an implementation of
+	  ntfs_write_inode() which for now just cleans dirty inodes without
+	  writing them (it does emit a warning that this is happening).
+
 2.1.11 - Driver internal cleanups.
 
 	- Only build logfile.o if building the driver with read-write support.
--- diff/fs/ntfs/Makefile	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ntfs/Makefile	2004-05-27 18:34:18.000000000 +0100
@@ -5,7 +5,7 @@
 ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
 	     mst.o namei.o super.o sysctl.o unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.11\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.12-WIP\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
--- diff/fs/ntfs/aops.c	2004-05-19 22:12:30.000000000 +0100
+++ source/fs/ntfs/aops.c	2004-05-27 18:34:18.000000000 +0100
@@ -1788,3 +1788,12 @@
 #endif
 };
 
+/**
+ * ntfs_mst_aops - general address space operations for mst protecteed inodes
+ *		   and attributes
+ */
+struct address_space_operations ntfs_mst_aops = {
+	.readpage	= ntfs_readpage,	/* Fill page with data. */
+	.sync_page	= block_sync_page,	/* Currently, just unplugs the
+						   disk request queue. */
+};
--- diff/fs/ntfs/dir.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ntfs/dir.c	2004-05-27 18:34:18.000000000 +0100
@@ -1196,7 +1196,7 @@
 	ia_mapping = vdir->i_mapping;
 	bmp_vi = ndir->itype.index.bmp_ino;
 	if (unlikely(!bmp_vi)) {
-		ntfs_debug("Inode %lu, regetting index bitmap.", vdir->i_ino);
+		ntfs_debug("Inode 0x%lx, regetting index bitmap.", vdir->i_ino);
 		bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
 		if (unlikely(IS_ERR(bmp_vi))) {
 			ntfs_error(sb, "Failed to get bitmap attribute.");
--- diff/fs/ntfs/inode.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ntfs/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -872,7 +872,7 @@
 		/* Setup the operations for this inode. */
 		vi->i_op = &ntfs_dir_inode_ops;
 		vi->i_fop = &ntfs_dir_ops;
-		vi->i_mapping->a_ops = &ntfs_aops;
+		vi->i_mapping->a_ops = &ntfs_mst_aops;
 	} else {
 		/* It is a file. */
 		reinit_attr_search_ctx(ctx);
@@ -1249,7 +1249,10 @@
 	/* Setup the operations for this attribute inode. */
 	vi->i_op = NULL;
 	vi->i_fop = NULL;
-	vi->i_mapping->a_ops = &ntfs_aops;
+	if (NInoMstProtected(ni))
+		vi->i_mapping->a_ops = &ntfs_mst_aops;
+	else
+		vi->i_mapping->a_ops = &ntfs_aops;
 
 	if (!NInoCompressed(ni))
 		vi->i_blocks = ni->allocated_size >> 9;
@@ -1339,7 +1342,7 @@
 	ni->name_len = 0;
 
 	/*
-	 * This sets up our little cheat allowing us to reuse the async io
+	 * This sets up our little cheat allowing us to reuse the async read io
 	 * completion handler for directories.
 	 */
 	ni->itype.index.block_size = vol->mft_record_size;
@@ -1703,18 +1706,6 @@
 }
 
 /**
- * ntfs_commit_inode - write out a dirty inode
- * @ni:		inode to write out
- *
- */
-int ntfs_commit_inode(ntfs_inode *ni)
-{
-	ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
-	NInoClearDirty(ni);
-	return 0;
-}
-
-/**
  * ntfs_put_inode - handler for when the inode reference count is decremented
  * @vi:		vfs inode
  *
@@ -1742,34 +1733,6 @@
 
 void __ntfs_clear_inode(ntfs_inode *ni)
 {
-	int err;
-
-	ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
-	if (NInoDirty(ni)) {
-		err = ntfs_commit_inode(ni);
-		if (err) {
-			ntfs_error(ni->vol->sb, "Failed to commit dirty "
-					"inode synchronously.");
-			// FIXME: Do something!!!
-		}
-	}
-	/* Synchronize with ntfs_commit_inode(). */
-	down(&ni->mrec_lock);
-	up(&ni->mrec_lock);
-	if (NInoDirty(ni)) {
-		ntfs_error(ni->vol->sb, "Failed to commit dirty inode "
-				"asynchronously.");
-		// FIXME: Do something!!!
-	}
-	/* No need to lock at this stage as no one else has a reference. */
-	if (ni->nr_extents > 0) {
-		int i;
-
-		// FIXME: Handle dirty case for each extent inode!
-		for (i = 0; i < ni->nr_extents; i++)
-			ntfs_clear_extent_inode(ni->ext.extent_ntfs_inos[i]);
-		kfree(ni->ext.extent_ntfs_inos);
-	}
 	/* Free all alocated memory. */
 	down_write(&ni->run_list.lock);
 	if (ni->run_list.rl) {
@@ -1799,6 +1762,20 @@
 
 void ntfs_clear_extent_inode(ntfs_inode *ni)
 {
+	ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
+
+	BUG_ON(NInoAttr(ni));
+	BUG_ON(ni->nr_extents != -1);
+
+#ifdef NTFS_RW
+	if (NInoDirty(ni)) {
+		if (!is_bad_inode(VFS_I(ni->ext.base_ntfs_ino)))
+			ntfs_error(ni->vol->sb, "Clearing dirty extent inode!  "
+					"Losing data!  This is a BUG!!!");
+		// FIXME:  Do something!!!
+	}
+#endif /* NTFS_RW */
+
 	__ntfs_clear_inode(ni);
 
 	/* Bye, bye... */
@@ -1819,6 +1796,30 @@
 {
 	ntfs_inode *ni = NTFS_I(vi);
 
+#ifdef NTFS_RW
+	if (NInoDirty(ni)) {
+		BOOL was_bad = (is_bad_inode(vi));
+
+		/* Committing the inode also commits all extent inodes. */
+		ntfs_commit_inode(vi);
+
+		if (!was_bad && (is_bad_inode(vi) || NInoDirty(ni))) {
+			ntfs_error(vi->i_sb, "Failed to commit dirty inode "
+					"0x%lx.  Losing data!", vi->i_ino);
+			// FIXME:  Do something!!!
+		}
+	}
+#endif /* NTFS_RW */
+
+	/* No need to lock at this stage as no one else has a reference. */
+	if (ni->nr_extents > 0) {
+		int i;
+
+		for (i = 0; i < ni->nr_extents; i++)
+			ntfs_clear_extent_inode(ni->ext.extent_ntfs_inos[i]);
+		kfree(ni->ext.extent_ntfs_inos);
+	}
+
 	__ntfs_clear_inode(ni);
 
 	if (NInoAttr(ni)) {
@@ -1959,4 +1960,49 @@
 	return err;
 }
 
-#endif
+void ntfs_write_inode(struct inode *vi, int sync)
+{
+	ntfs_inode *ni = NTFS_I(vi);
+
+	ntfs_debug("Entering for %sinode 0x%lx.", NInoAttr(ni) ? "attr " : "",
+			vi->i_ino);
+
+	/*
+	 * Dirty attribute inodes are written via their real inodes so just
+	 * clean them here.
+	 */
+	if (NInoAttr(ni)) {
+		NInoClearDirty(ni);
+		return;
+	}
+
+	/* Write this base mft record. */
+	if (NInoDirty(ni)) {
+		ntfs_warning(vi->i_sb, "Cleaning dirty inode 0x%lx without "
+				"writing to disk as this is not yet "
+				"implemented.", vi->i_ino);
+		NInoClearDirty(ni);
+	}
+
+	/* Write all attached extent mft records. */
+	down(&ni->extent_lock);
+	if (ni->nr_extents > 0) {
+		int i;
+		ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos;
+
+		for (i = 0; i < ni->nr_extents; i++) {
+			ntfs_inode *tni = extent_nis[i];
+
+			if (NInoDirty(tni)) {
+				ntfs_warning(vi->i_sb, "Cleaning dirty extent "
+						"inode 0x%lx without writing "
+						"to disk as this is not yet "
+						"implemented.", tni->mft_no);
+				NInoClearDirty(tni);
+			}
+		}
+	}
+	up(&ni->extent_lock);
+}
+
+#endif /* NTFS_RW */
--- diff/fs/ntfs/inode.h	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ntfs/inode.h	2004-05-27 18:34:18.000000000 +0100
@@ -281,6 +281,15 @@
 
 extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr);
 
+extern void ntfs_write_inode(struct inode *vi, int sync);
+
+static inline void ntfs_commit_inode(struct inode *vi)
+{
+	if (!is_bad_inode(vi))
+		ntfs_write_inode(vi, 1);
+	return;
+}
+
 #endif /* NTFS_RW */
 
 #endif /* _LINUX_NTFS_INODE_H */
--- diff/fs/ntfs/ntfs.h	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ntfs/ntfs.h	2004-05-27 18:34:18.000000000 +0100
@@ -62,6 +62,7 @@
 /* The various operations structs defined throughout the driver files. */
 extern struct super_operations ntfs_sops;
 extern struct address_space_operations ntfs_aops;
+extern struct address_space_operations ntfs_mst_aops;
 extern struct address_space_operations ntfs_mft_aops;
 
 extern struct  file_operations ntfs_file_ops;
--- diff/fs/ntfs/super.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/ntfs/super.c	2004-05-27 18:34:18.000000000 +0100
@@ -763,7 +763,7 @@
 	/* The $MFTMirr, like the $MFT is multi sector transfer protected. */
 	NInoSetMstProtected(tmp_ni);
 	/*
-	 * Set up our little cheat allowing us to reuse the async io
+	 * Set up our little cheat allowing us to reuse the async read io
 	 * completion handler for directories.
 	 */
 	tmp_ni->itype.index.block_size = vol->mft_record_size;
--- diff/fs/open.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/open.c	2004-05-27 18:34:18.000000000 +0100
@@ -790,7 +790,6 @@
 	}
 
 	f->f_mapping = inode->i_mapping;
-	file_ra_state_init(&f->f_ra, f->f_mapping);
 	f->f_dentry = dentry;
 	f->f_vfsmnt = mnt;
 	f->f_pos = 0;
@@ -804,12 +803,13 @@
 	}
 	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 
+	file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
+
 	/* NB: we're sure to have correct a_ops only after f_op->open */
 	if (f->f_flags & O_DIRECT) {
-		if (!f->f_mapping || !f->f_mapping->a_ops ||
-			!f->f_mapping->a_ops->direct_IO) {
-				fput(f);
-				f = ERR_PTR(-EINVAL);
+		if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) {
+			fput(f);
+			f = ERR_PTR(-EINVAL);
 		}
 	}
 
--- diff/fs/partitions/Kconfig	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/partitions/Kconfig	2004-05-27 18:34:18.000000000 +0100
@@ -187,13 +187,6 @@
 
 	  If unsure, say N.
 
-config NEC98_PARTITION
-	bool "NEC PC-9800 partition table support" if PARTITION_ADVANCED
-	default y if !PARTITION_ADVANCED && X86_PC9800
-	help
-	  Say Y here if you would like to be able to read the hard disk
-	  partition table format used by NEC PC-9800 machines.
-
 config SGI_PARTITION
 	bool "SGI partition support" if PARTITION_ADVANCED
 	default y if !PARTITION_ADVANCED && (SGI_IP22 || SGI_IP27)
--- diff/fs/partitions/check.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/partitions/check.c	2004-05-27 18:34:18.000000000 +0100
@@ -29,7 +29,6 @@
 #include "ldm.h"
 #include "mac.h"
 #include "msdos.h"
-#include "nec98.h"
 #include "osf.h"
 #include "sgi.h"
 #include "sun.h"
--- diff/fs/partitions/msdos.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/partitions/msdos.c	2004-05-27 18:34:18.000000000 +0100
@@ -389,8 +389,23 @@
 		put_dev_sector(sect);
 		return 0;
 	}
+
+	/*
+	 * Now that the 55aa signature is present, this is probably
+	 * either the boot sector of a FAT filesystem or a DOS-type
+	 * partition table. Reject this in case the boot indicator
+	 * is not 0 or 0x80.
+	 */
 	p = (struct partition *) (data + 0x1be);
+	for (slot = 1; slot <= 4; slot++, p++) {
+		if (p->boot_ind != 0 && p->boot_ind != 0x80) {
+			put_dev_sector(sect);
+			return 0;
+		}
+	}
+
 #ifdef CONFIG_EFI_PARTITION
+	p = (struct partition *) (data + 0x1be);
 	for (slot = 1 ; slot <= 4 ; slot++, p++) {
 		/* If this is an EFI GPT disk, msdos should ignore it. */
 		if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
@@ -398,8 +413,8 @@
 			return 0;
 		}
 	}
-	p = (struct partition *) (data + 0x1be);
 #endif
+	p = (struct partition *) (data + 0x1be);
 
 	/*
 	 * Look for partitions in two passes:
--- diff/fs/proc/array.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/proc/array.c	2004-05-27 18:34:18.000000000 +0100
@@ -149,6 +149,7 @@
 
 static inline char * task_state(struct task_struct *p, char *buffer)
 {
+	struct group_info *group_info;
 	int g;
 
 	read_lock(&tasklist_lock);
@@ -174,12 +175,14 @@
 		"FDSize:\t%d\n"
 		"Groups:\t",
 		p->files ? p->files->max_fds : 0);
+
+	group_info = p->group_info;
+	get_group_info(group_info);
 	task_unlock(p);
 
-	get_group_info(p->group_info);
-	for (g = 0; g < min(p->group_info->ngroups,NGROUPS_SMALL); g++)
-		buffer += sprintf(buffer, "%d ", GROUP_AT(p->group_info,g));
-	put_group_info(p->group_info);
+	for (g = 0; g < min(group_info->ngroups,NGROUPS_SMALL); g++)
+		buffer += sprintf(buffer, "%d ", GROUP_AT(group_info,g));
+	put_group_info(group_info);
 
 	buffer += sprintf(buffer, "\n");
 	return buffer;
--- diff/fs/proc/generic.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/proc/generic.c	2004-05-27 18:34:18.000000000 +0100
@@ -288,18 +288,20 @@
  */
 static unsigned int get_inode_number(void)
 {
-	unsigned int i, inum = 0;
+	int i, inum = 0;
+	int error;
 
 retry:
 	if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0)
 		return 0;
 
 	spin_lock(&proc_inum_lock);
-	i = idr_get_new(&proc_inum_idr, NULL);
+	error = idr_get_new(&proc_inum_idr, NULL, &i);
 	spin_unlock(&proc_inum_lock);
-
-	if (i == -1)
+	if (error == -EAGAIN)
 		goto retry;
+	else if (error)
+		return 0;
 
 	inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST;
 
@@ -319,21 +321,14 @@
 	spin_unlock(&proc_inum_lock);
 }
 
-static int
-proc_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	char *s = PDE(dentry->d_inode)->data;
-	return vfs_readlink(dentry, buffer, buflen, s);
-}
-
 static int proc_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = PDE(dentry->d_inode)->data;
-	return vfs_follow_link(nd, s);
+	nd_set_link(nd, PDE(dentry->d_inode)->data);
+	return 0;
 }
 
 static struct inode_operations proc_link_inode_operations = {
-	.readlink	= proc_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= proc_follow_link,
 };
 
--- diff/fs/proc/kcore.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/proc/kcore.c	2004-05-27 18:34:18.000000000 +0100
@@ -18,6 +18,7 @@
 #include <linux/elfcore.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -84,8 +85,6 @@
 	return 0;
 }
 
-extern char saved_command_line[];
-
 static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
 {
 	size_t try, size;
--- diff/fs/proc/proc_misc.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/proc/proc_misc.c	2004-05-27 18:34:18.000000000 +0100
@@ -47,7 +47,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 #include <asm/tlb.h>
 #include <asm/div64.h>
 
@@ -286,6 +285,10 @@
 	.release	= seq_release,
 };
 
+#ifdef CONFIG_SCHEDSTATS
+extern struct file_operations proc_schedstat_operations;
+#endif
+
 #ifdef CONFIG_PROC_HARDWARE
 static int hardware_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -522,7 +525,6 @@
 static int cmdline_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
-	extern char saved_command_line[];
 	int len;
 
 	len = sprintf(page, "%s\n", saved_command_line);
@@ -651,6 +653,36 @@
 		entry->proc_fops = f;
 }
 
+#ifdef CONFIG_LOCKMETER
+extern ssize_t get_lockmeter_info(char *, size_t, loff_t *);
+extern ssize_t put_lockmeter_info(const char *, size_t);
+extern int get_lockmeter_info_size(void);
+
+/*
+ * This function accesses lock metering information.
+ */
+static ssize_t read_lockmeter(struct file *file, char *buf,
+			      size_t count, loff_t *ppos)
+{
+	return get_lockmeter_info(buf, count, ppos);
+}
+
+/*
+ * Writing to /proc/lockmeter resets the counters
+ */
+static ssize_t write_lockmeter(struct file * file, const char * buf,
+			       size_t count, loff_t *ppos)
+{
+	return put_lockmeter_info(buf, count);
+}
+
+static struct file_operations proc_lockmeter_operations = {
+	NULL,           /* lseek */
+	read:		read_lockmeter,
+	write:		write_lockmeter,
+};
+#endif  /* CONFIG_LOCKMETER */
+
 void __init proc_misc_init(void)
 {
 	struct proc_dir_entry *entry;
@@ -698,6 +730,9 @@
 #ifdef CONFIG_MODULES
 	create_seq_entry("modules", 0, &proc_modules_operations);
 #endif
+#ifdef CONFIG_SCHEDSTATS
+	create_seq_entry("schedstat", 0, &proc_schedstat_operations);
+#endif
 #ifdef CONFIG_PROC_KCORE
 	proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
 	if (proc_root_kcore) {
@@ -718,6 +753,13 @@
 	if (entry)
 		entry->proc_fops = &proc_sysrq_trigger_operations;
 #endif
+#ifdef CONFIG_LOCKMETER
+	entry = create_proc_entry("lockmeter", S_IWUSR | S_IRUGO, NULL);
+	if (entry) {
+		entry->proc_fops = &proc_lockmeter_operations;
+		entry->size = get_lockmeter_info_size();
+	}
+#endif
 #ifdef CONFIG_PPC32
 	{
 		extern struct file_operations ppc_htab_operations;
--- diff/fs/reiserfs/bitmap.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/reiserfs/bitmap.c	2004-05-27 18:34:18.000000000 +0100
@@ -30,6 +30,9 @@
 #define  _ALLOC_hashed_formatted_nodes 7
 #define  _ALLOC_old_way 8
 #define  _ALLOC_hundredth_slices 9
+#define  _ALLOC_dirid_groups 10
+#define  _ALLOC_oid_groups 11
+#define  _ALLOC_packing_groups 12
 
 #define  concentrating_formatted_nodes(s)	test_bit(_ALLOC_concentrating_formatted_nodes, &SB_ALLOC_OPTS(s))
 #define  displacing_large_files(s)		test_bit(_ALLOC_displacing_large_files, &SB_ALLOC_OPTS(s))
@@ -150,11 +153,6 @@
        __wait_on_buffer (bi->bh);
     }
 
-    /* If we know that first zero bit is only one or first zero bit is
-       closer to the end of bitmap than our start pointer */
-    if (bi->first_zero_hint > *beg || bi->free_count == 1)
-	*beg = bi->first_zero_hint;
-
     while (1) {
 	cont:
 	if (bi->free_count < min)
@@ -204,21 +202,12 @@
 		    while (--i >= *beg)
 			reiserfs_test_and_clear_le_bit (i, bi->bh->b_data);
 		    reiserfs_restore_prepared_buffer (s, bi->bh);
-		    *beg = max(org, (int)bi->first_zero_hint);
+		    *beg = org;
 		    /* ... and search again in current block from beginning */
 		    goto cont;	
 		}
 	    }
 	    bi->free_count -= (end - *beg);
-
-	    /* if search started from zero_hint bit, and zero hint have not
-                changed since, then we need to update first_zero_hint */
-	    if ( bi->first_zero_hint >= *beg)
-		/* no point in looking for free bit if there is not any */
-		bi->first_zero_hint = (bi->free_count > 0 ) ?
-			reiserfs_find_next_zero_le_bit
-			((unsigned long*)(bi->bh->b_data), s->s_blocksize << 3, end) : (s->s_blocksize << 3);
-
 	    journal_mark_dirty (th, s, bi->bh);
 
 	    /* free block count calculation */
@@ -231,7 +220,57 @@
 	    *beg = next;
 	}
     }
-  }
+}
+
+static int bmap_hash_id(struct super_block *s, u32 id) {
+    char * hash_in = NULL;
+    unsigned long hash;
+    unsigned bm;
+
+    if (id <= 2) {
+	bm = 1;
+    } else {
+        hash_in = (char *)(&id);
+        hash = keyed_hash(hash_in, 4);
+	bm = hash % SB_BMAP_NR(s);
+	if (!bm)
+	    bm = 1;
+    }
+    return bm;
+}
+
+/*
+ * hashes the id and then returns > 0 if the block group for the
+ * corresponding hash is full
+ */
+static inline int block_group_used(struct super_block *s, u32 id) {
+    int bm;
+    bm = bmap_hash_id(s, id);
+    if (SB_AP_BITMAP(s)[bm].free_count > ((s->s_blocksize << 3) * 60 / 100) ) {
+        return 0;
+    }
+    return 1;
+}
+
+/*
+ * the packing is returned in disk byte order
+ */
+u32 reiserfs_choose_packing(struct inode *dir) {
+    u32 packing;
+    if (TEST_OPTION(packing_groups, dir->i_sb)) {
+	u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id);
+	/*
+	 * some versions of reiserfsck expect packing locality 1 to be
+	 * special
+	 */
+	if (parent_dir == 1 || block_group_used(dir->i_sb,parent_dir))
+            packing = INODE_PKEY(dir)->k_objectid;
+        else
+            packing = INODE_PKEY(dir)->k_dir_id;
+    } else
+        packing = INODE_PKEY(dir)->k_objectid;
+    return packing;
+}
   
 /* Tries to find contiguous zero bit window (given size) in given region of
  * bitmap and place new blocks there. Returns number of allocated blocks. */
@@ -255,8 +294,18 @@
     get_bit_address (s, *start, &bm, &off);
     get_bit_address (s, finish, &end_bm, &end_off);
 
-    // With this option set first we try to find a bitmap that is at least 10%
-    // free, and if that fails, then we fall back to old whole bitmap scanning
+    /* When the bitmap is more than 10% free, anyone can allocate.
+     * When it's less than 10% free, only files that already use the
+     * bitmap are allowed. Once we pass 80% full, this restriction
+     * is lifted.
+     *
+     * We do this so that files that grow later still have space close to
+     * their original allocation. This improves locality, and presumably
+     * performance as a result.
+     *
+     * This is only an allocation policy and does not make up for getting a
+     * bad hint. Decent hinting must be implemented for this to work well.
+     */
     if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) {
 	for (;bm < end_bm; bm++, off = 0) {
 	    if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 )
@@ -314,9 +363,6 @@
 			  "free_block (%s:%lu)[dev:blocknr]: bit already cleared",
 			  reiserfs_bdevname (s), block);
     }
-    if (offset < apbi[nr].first_zero_hint) {
-      apbi[nr].first_zero_hint = offset;
-    }
     apbi[nr].free_count ++;
     journal_mark_dirty (th, s, apbi[nr].bh);
 
@@ -396,6 +442,14 @@
 	__discard_prealloc(th, ei);
     }
 }
+
+void reiserfs_init_alloc_options (struct super_block *s)
+{
+    set_bit (_ALLOC_skip_busy, &SB_ALLOC_OPTS(s));
+    set_bit (_ALLOC_dirid_groups, &SB_ALLOC_OPTS(s));
+    set_bit (_ALLOC_packing_groups, &SB_ALLOC_OPTS(s));
+}
+
 /* block allocator related options are parsed here */
 int reiserfs_parse_alloc_options(struct super_block * s, char * options)
 {
@@ -439,6 +493,18 @@
 	    continue;
 	}
 
+        if (!strcmp(this_char, "dirid_groups")) {
+	    SET_OPTION(dirid_groups);
+	    continue;
+        }
+        if (!strcmp(this_char, "oid_groups")) {
+	    SET_OPTION(oid_groups);
+	    continue;
+        }
+        if (!strcmp(this_char, "packing_groups")) {
+	    SET_OPTION(packing_groups);
+	    continue;
+        }
 	if (!strcmp(this_char, "hashed_formatted_nodes")) {
 	    SET_OPTION(hashed_formatted_nodes);
 	    continue;
@@ -481,6 +547,7 @@
 	return 1;
       }
   
+    reiserfs_warning (s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s));
     return 0;
 }
   
@@ -503,17 +570,76 @@
     hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
 }
 
-static inline void get_left_neighbor(reiserfs_blocknr_hint_t *hint)
+/*
+ * Relocation based on dirid, hashing them into a given bitmap block
+ * files. Formatted nodes are unaffected, a seperate policy covers them
+ */
+static void
+dirid_groups (reiserfs_blocknr_hint_t *hint)
+{
+    unsigned long hash;
+    __u32 dirid = 0;
+    int bm = 0;
+    struct super_block *sb = hint->th->t_super;
+    if (hint->inode)
+	dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
+    else if (hint->formatted_node)
+        dirid = hint->key.k_dir_id;
+
+    if (dirid) {
+	bm = bmap_hash_id(sb, dirid);
+	hash = bm * (sb->s_blocksize << 3);
+	/* give a portion of the block group to metadata */
+	if (hint->inode)
+	    hash += sb->s_blocksize/2;
+	hint->search_start = hash;
+    }
+}
+
+/*
+ * Relocation based on oid, hashing them into a given bitmap block
+ * files. Formatted nodes are unaffected, a seperate policy covers them
+ */
+static void
+oid_groups (reiserfs_blocknr_hint_t *hint)
+{
+    if (hint->inode) {
+	unsigned long hash;
+	__u32 oid;
+	__u32 dirid;
+	int bm;
+
+	dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
+
+	/* keep the root dir and it's first set of subdirs close to
+	 * the start of the disk
+	 */
+	if (dirid <= 2)
+	    hash = (hint->inode->i_sb->s_blocksize << 3);
+	else {
+	    oid = le32_to_cpu(INODE_PKEY(hint->inode)->k_objectid);
+	    bm = bmap_hash_id(hint->inode->i_sb, oid);
+	    hash = bm * (hint->inode->i_sb->s_blocksize << 3);
+	}
+	hint->search_start = hash;
+    }
+}
+
+/* returns 1 if it finds an indirect item and gets valid hint info
+ * from it, otherwise 0
+ */
+static int get_left_neighbor(reiserfs_blocknr_hint_t *hint)
 {
     struct path * path;
     struct buffer_head * bh;
     struct item_head * ih;
     int pos_in_item;
     __u32 * item;
+    int ret = 0;
 
     if (!hint->path)		/* reiserfs code can call this function w/o pointer to path
 				 * structure supplied; then we rely on supplied search_start */
-	return;
+	return 0;
 
     path = hint->path;
     bh = get_last_bh(path);
@@ -534,15 +660,15 @@
 	    int t=get_block_num(item,pos_in_item);
 	    if (t) {
 		hint->search_start = t;
+		ret = 1;
 		break;
 	    }
 	    pos_in_item --;
 	}
-    } else {
-      }
+    }
 
     /* does result value fit into specified region? */
-    return;
+    return ret;
 }
 
 /* should be, if formatted node, then try to put on first part of the device
@@ -639,10 +765,12 @@
     }
 }
   
-static inline void determine_search_start(reiserfs_blocknr_hint_t *hint,
+static void determine_search_start(reiserfs_blocknr_hint_t *hint,
 					  int amount_needed)
 {
     struct super_block *s = hint->th->t_super;
+    int unfm_hint;
+
     hint->beg = 0;
     hint->end = SB_BLOCK_COUNT(s) - 1;
 
@@ -673,19 +801,14 @@
 	return;
     }
 
-    /* attempt to copy a feature from old block allocator code */
-    if (TEST_OPTION(old_hashed_relocation, s) && !hint->formatted_node) {
-	old_hashed_relocation(hint);
-    }
-
     /* if none of our special cases is relevant, use the left neighbor in the
        tree order of the new node we are allocating for */
     if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes,s)) {
-	hash_formatted_node(hint);
+        hash_formatted_node(hint);
 	return;
-    } 
+    }
 
-    get_left_neighbor(hint);
+    unfm_hint = get_left_neighbor(hint);
 
     /* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,
        new blocks are displaced based on directory ID. Also, if suggested search_start
@@ -710,10 +833,36 @@
 	return;
     }
 
-    if (TEST_OPTION(old_hashed_relocation, s))
+    /* old_hashed_relocation only works on unformatted */
+    if (!unfm_hint && !hint->formatted_node &&
+        TEST_OPTION(old_hashed_relocation, s))
+    {
 	old_hashed_relocation(hint);
-    if (TEST_OPTION(new_hashed_relocation, s))
+    }
+    /* new_hashed_relocation works with both formatted/unformatted nodes */
+    if ((!unfm_hint || hint->formatted_node) &&
+        TEST_OPTION(new_hashed_relocation, s))
+    {
 	new_hashed_relocation(hint);
+    }
+    /* dirid grouping works only on unformatted nodes */
+    if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups,s))
+    {
+        dirid_groups(hint);
+    }
+
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    if (hint->formatted_node && TEST_OPTION(dirid_groups,s))
+    {
+        dirid_groups(hint);
+    }
+#endif
+
+    /* oid grouping works only on unformatted nodes */
+    if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups,s))
+    {
+        oid_groups(hint);
+    }
     return;
 }
 
@@ -738,13 +887,14 @@
 static inline int allocate_without_wrapping_disk (reiserfs_blocknr_hint_t * hint,
 					 b_blocknr_t * new_blocknrs,
 					 b_blocknr_t start, b_blocknr_t finish,
+					 int min,
 					 int amount_needed, int prealloc_size)
 {
     int rest = amount_needed;
     int nr_allocated;
   
     while (rest > 0 && start <= finish) {
-	nr_allocated = scan_bitmap (hint->th, &start, finish, 1,
+	nr_allocated = scan_bitmap (hint->th, &start, finish, min,
 				    rest + prealloc_size, !hint->formatted_node,
 				    hint->block);
 
@@ -777,8 +927,9 @@
     struct super_block *s = hint->th->t_super;
     b_blocknr_t start = hint->search_start;
     b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
-    int second_pass = 0;
+    int passno = 0;
     int nr_allocated = 0;
+    int bigalloc = 0;
 
     determine_prealloc_size(hint);
     if (!hint->formatted_node) {
@@ -797,32 +948,64 @@
 	    if (quota_ret)
 		hint->preallocate=hint->prealloc_size=0;
 	}
-    }
-
-    while((nr_allocated
-	  += allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish,
-					  amount_needed - nr_allocated, hint->prealloc_size))
-	  < amount_needed) {
-
-	/* not all blocks were successfully allocated yet*/
-	if (second_pass) {	/* it was a second pass; we must free all blocks */
+	/* for unformatted nodes, force large allocations */
+	bigalloc = amount_needed + hint->prealloc_size;
+	/* try to make things even */
+	if (bigalloc & 1 && hint->prealloc_size)
+	    bigalloc--;
+    }
+
+    do {
+	/* in bigalloc mode, nr_allocated should stay zero until
+	 * the entire allocation is filled
+	 */
+	if (unlikely(bigalloc && nr_allocated)) {
+	    reiserfs_warning(s, "bigalloc is %d, nr_allocated %d\n",
+	    bigalloc, nr_allocated);
+	    /* reset things to a sane value */
+	    bigalloc = amount_needed - nr_allocated;
+	}
+	/*
+	 * try pass 0 and pass 1 looking for a nice big
+	 * contiguous allocation.  Then reset and look
+	 * for anything you can find.
+	 */
+	if (passno == 2 && bigalloc) {
+	    passno = 0;
+	    bigalloc = 0;
+	}
+	switch (passno++) {
+        case 0: /* Search from hint->search_start to end of disk */
+	    start = hint->search_start;
+	    finish = SB_BLOCK_COUNT(s) - 1;
+	    break;
+        case 1: /* Search from hint->beg to hint->search_start */
+	    start = hint->beg;
+	    finish = hint->search_start;
+	    break;
+	case 2: /* Last chance: Search from 0 to hint->beg */
+	    start = 0;
+	    finish = hint->beg;
+	    break;
+	default: /* We've tried searching everywhere, not enough space */
+	    /* Free the blocks */
 	    if (!hint->formatted_node) {
 #ifdef REISERQUOTA_DEBUG
 		reiserfs_debug (s, "reiserquota: freeing (nospace) %d blocks id=%u", amount_needed + hint->prealloc_size - nr_allocated, hint->inode->i_uid);
 #endif
 		DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated);     /* Free not allocated blocks */
 	    }
-	    while (nr_allocated --)
+  	    while (nr_allocated --)
 		reiserfs_free_block(hint->th, hint->inode, new_blocknrs[nr_allocated], !hint->formatted_node);
 
 	    return NO_DISK_SPACE;
-	} else {		/* refine search parameters for next pass */
-	    second_pass = 1;
-	    finish = start;
-	    start = 0;
-	    continue;
 	}
-    }
+    } while ((nr_allocated += allocate_without_wrapping_disk (hint,
+			    new_blocknrs + nr_allocated, start, finish,
+			    bigalloc ? bigalloc : 1,
+			    amount_needed - nr_allocated,
+			    hint->prealloc_size))
+			< amount_needed);
     if ( !hint->formatted_node &&
          amount_needed + hint->prealloc_size >
 	 nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
--- diff/fs/reiserfs/dir.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/reiserfs/dir.c	2004-05-27 18:34:18.000000000 +0100
@@ -64,6 +64,7 @@
 
     /*  reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos);*/
 
+    path_to_entry.reada = PATH_READA;
     while (1) {
     research:
 	/* search the directory item, containing entry with specified key */
--- diff/fs/reiserfs/file.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/reiserfs/file.c	2004-05-27 18:34:18.000000000 +0100
@@ -89,15 +89,16 @@
 			      ) {
   struct inode * p_s_inode = p_s_dentry->d_inode;
   int n_err;
-
-  reiserfs_write_lock(p_s_inode->i_sb);
+  int barrier_done;
 
   if (!S_ISREG(p_s_inode->i_mode))
       BUG ();
-
   n_err = sync_mapping_buffers(p_s_inode->i_mapping) ;
-  reiserfs_commit_for_inode(p_s_inode) ;
+  reiserfs_write_lock(p_s_inode->i_sb);
+  barrier_done = reiserfs_commit_for_inode(p_s_inode);
   reiserfs_write_unlock(p_s_inode->i_sb);
+  if (barrier_done != 1)
+      blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
   return ( n_err < 0 ) ? -EIO : 0;
 }
 
@@ -176,12 +177,13 @@
     hint.formatted_node = 0; // We are allocating blocks for unformatted node.
 
     /* only preallocate if this is a small write */
-    if (blocks_to_allocate <
-        REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize)
+    if (REISERFS_I(inode)->i_prealloc_count ||
+       (!(write_bytes & (inode->i_sb->s_blocksize -1)) &&
+        blocks_to_allocate <
+        REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize))
         hint.preallocate = 1;
     else
         hint.preallocate = 0;
-
     /* Call block allocator to allocate blocks */
     res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate);
     if ( res != CARRY_ON ) {
@@ -467,6 +469,12 @@
     // the inode.
     //
     pathrelse(&path);
+    /*
+     * cleanup prellocation from previous writes
+     * if this is a partial block write
+     */
+    if (write_bytes & (inode->i_sb->s_blocksize -1))
+        reiserfs_discard_prealloc(th, inode);
     reiserfs_write_unlock(inode->i_sb);
 
     // go through all the pages/buffers and map the buffers to newly allocated
@@ -585,9 +593,19 @@
     struct buffer_head *bh, *head;
     unsigned long i_size_index = inode->i_size >> PAGE_CACHE_SHIFT;
     int new;
+    int logit = reiserfs_file_data_log(inode);
+    struct super_block *s = inode->i_sb;
+    int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
+    struct reiserfs_transaction_handle th;
+    th.t_trans_id = 0;
 
     blocksize = 1 << inode->i_blkbits;
 
+    if (logit) {
+	reiserfs_write_lock(s);
+	journal_begin(&th, s, bh_per_page + 1);
+	reiserfs_update_inode_transaction(inode);
+    }
     for(bh = head = page_buffers(page), block_start = 0;
         bh != head || !block_start;
 	block_start=block_end, bh = bh->b_this_page)
@@ -601,7 +619,10 @@
 		    partial = 1;
 	} else {
 	    set_buffer_uptodate(bh);
-	    if (!buffer_dirty(bh)) {
+	    if (logit) {
+		reiserfs_prepare_for_journal(s, bh, 1);
+		journal_mark_dirty(&th, s, bh);
+	    } else if (!buffer_dirty(bh)) {
 		mark_buffer_dirty(bh);
 		/* do data=ordered on any page past the end
 		 * of file and any buffer marked BH_New.
@@ -613,7 +634,10 @@
 	    }
 	}
     }
-
+    if (logit) {
+	journal_end(&th, s, bh_per_page + 1);
+	reiserfs_write_unlock(s);
+    }
     /*
      * If this is a partial write which happened to make all buffers
      * uptodate then we can optimize away a bogus readpage() for
@@ -1254,6 +1278,7 @@
 	journal_end(&th, th.t_super, th.t_blocks_allocated);
         reiserfs_write_unlock(inode->i_sb);
     }
+
     if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
 	res = generic_osync_inode(inode, file->f_mapping, OSYNC_METADATA|OSYNC_DATA);
 
--- diff/fs/reiserfs/inode.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/reiserfs/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -1660,7 +1660,7 @@
     sb = dir->i_sb;
 
     /* item head of new item */
-    ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
+    ih.ih_key.k_dir_id = reiserfs_choose_packing(dir);
     ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
     if (!ih.ih_key.k_objectid) {
 	err = -ENOMEM;
@@ -1729,7 +1729,6 @@
 	err = -EEXIST;
 	goto out_bad_inode;
     }
-
     if (old_format_only (sb)) {
 	if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
 	    pathrelse (&path_to_key);
@@ -2148,6 +2147,11 @@
     struct buffer_head *head, *bh;
     int partial = 0 ;
     int nr = 0;
+    int checked = PageChecked(page);
+    struct reiserfs_transaction_handle th;
+    struct super_block *s = inode->i_sb;
+    int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
+    th.t_trans_id = 0;
 
     /* The page dirty bit is cleared before writepage is called, which
      * means we have to tell create_empty_buffers to make dirty buffers
@@ -2155,7 +2159,7 @@
      * in the BH_Uptodate is just a sanity check.
      */
     if (!page_has_buffers(page)) {
-	create_empty_buffers(page, inode->i_sb->s_blocksize, 
+	create_empty_buffers(page, s->s_blocksize,
 	                    (1 << BH_Dirty) | (1 << BH_Uptodate));
     }
     head = page_buffers(page) ;
@@ -2179,10 +2183,10 @@
 	kunmap_atomic(kaddr, KM_USER0) ;
     }
     bh = head ;
-    block = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits) ;
+    block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits) ;
     /* first map all the buffers, logging any direct items we find */
     do {
-	if (buffer_dirty(bh) && (!buffer_mapped(bh) ||
+	if ((checked || buffer_dirty(bh)) && (!buffer_mapped(bh) ||
 	   (buffer_mapped(bh) && bh->b_blocknr == 0))) {
 	    /* not mapped yet, or it points to a direct item, search
 	     * the btree for the mapping info, and log any direct
@@ -2196,6 +2200,18 @@
 	block++;
     } while(bh != head) ;
 
+    /*
+     * we start the transaction after map_block_for_writepage,
+     * because it can create holes in the file (an unbounded operation).
+     * starting it here, we can make a reliable estimate for how many
+     * blocks we're going to log
+     */
+    if (checked) {
+	ClearPageChecked(page);
+	reiserfs_write_lock(s);
+	journal_begin(&th, s, bh_per_page + 1);
+	reiserfs_update_inode_transaction(inode);
+    }
     /* now go through and lock any dirty buffers on the page */
     do {
 	get_bh(bh);
@@ -2204,6 +2220,11 @@
 	if (buffer_mapped(bh) && bh->b_blocknr == 0)
 	    continue;
 
+	if (checked) {
+	    reiserfs_prepare_for_journal(s, bh, 1);
+	    journal_mark_dirty(&th, s, bh);
+	    continue;
+	}
 	/* from this point on, we know the buffer is mapped to a
 	 * real block and not a direct item
 	 */
@@ -2222,6 +2243,10 @@
 	}
     } while((bh = bh->b_this_page) != head);
 
+    if (checked) {
+	journal_end(&th, s, bh_per_page + 1);
+	reiserfs_write_unlock(s);
+    }
     BUG_ON(PageWriteback(page));
     set_page_writeback(page);
     unlock_page(page);
@@ -2481,17 +2506,15 @@
     /* the page is locked, and the only places that log a data buffer
      * also lock the page.
      */
-#if 0
     if (reiserfs_file_data_log(inode)) {
-	/* very conservative, leave the buffer pinned if anyone might need it.
-	** this should be changed to drop the buffer if it is only in the
-	** current transaction
-	*/
+	/*
+	 * very conservative, leave the buffer pinned if
+	 * anyone might need it.
+	 */
         if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
 	    ret = 0 ;
 	}
     } else
-#endif
     if (buffer_dirty(bh) || buffer_locked(bh)) {
 	struct reiserfs_journal_list *jl;
 	struct reiserfs_jh *jh = bh->b_private;
@@ -2529,6 +2552,10 @@
     int ret = 1;
 
     BUG_ON(!PageLocked(page));
+
+    if (offset == 0)
+	ClearPageChecked(page);
+
     if (!page_has_buffers(page))
 	goto out;
 
@@ -2562,6 +2589,15 @@
     return ret;
 }
 
+static int reiserfs_set_page_dirty(struct page *page) {
+    struct inode *inode = page->mapping->host;
+    if (reiserfs_file_data_log(inode)) {
+	SetPageChecked(page);
+	return __set_page_dirty_nobuffers(page);
+    }
+    return __set_page_dirty_buffers(page);
+}
+
 /*
  * Returns 1 if the page's buffers were dropped.  The page is locked.
  *
@@ -2579,6 +2615,7 @@
     struct buffer_head *bh ;
     int ret = 1 ;
 
+    WARN_ON(PageChecked(page));
     spin_lock(&j->j_dirty_buffers_lock) ;
     head = page_buffers(page) ;
     bh = head ;
@@ -2684,5 +2721,6 @@
     .prepare_write = reiserfs_prepare_write,
     .commit_write = reiserfs_commit_write,
     .bmap = reiserfs_aop_bmap,
-    .direct_IO = reiserfs_direct_IO
+    .direct_IO = reiserfs_direct_IO,
+    .set_page_dirty = reiserfs_set_page_dirty,
 } ;
--- diff/fs/reiserfs/journal.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/reiserfs/journal.c	2004-05-27 18:34:18.000000000 +0100
@@ -127,6 +127,12 @@
   return 0 ;
 }
 
+static void disable_barrier(struct super_block *s)
+{
+    REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_BARRIER_FLUSH);
+    printk("reiserfs: disabling flush barriers on %s\n", reiserfs_bdevname(s));
+}
+
 static struct reiserfs_bitmap_node *
 allocate_bitmap_node(struct super_block *p_s_sb) {
   struct reiserfs_bitmap_node *bn ;
@@ -640,6 +646,15 @@
     submit_bh(WRITE, bh) ;
 }
 
+static int submit_barrier_buffer(struct buffer_head *bh) {
+    get_bh(bh) ;
+    bh->b_end_io = reiserfs_end_ordered_io;
+    clear_buffer_dirty(bh) ;
+    if (!buffer_uptodate(bh))
+        BUG();
+    return submit_bh(WRITE_BARRIER, bh) ;
+}
+
 #define CHUNK_SIZE 32
 struct buffer_chunk {
     struct buffer_head *bh[CHUNK_SIZE];
@@ -909,6 +924,7 @@
   int bn ;
   struct buffer_head *tbh = NULL ;
   unsigned long trans_id = jl->j_trans_id;
+  int barrier = 0;
 
   reiserfs_check_lock_depth(s, "flush_commit_list") ;
 
@@ -973,7 +989,20 @@
   }
   atomic_dec(&SB_JOURNAL(s)->j_async_throttle);
 
-  /* wait on everything written so far before writing the commit */
+  /* wait on everything written so far before writing the commit
+   * if we are in barrier mode, send the commit down now
+   */
+  barrier = reiserfs_barrier_flush(s);
+  if (barrier) {
+      int ret;
+      lock_buffer(jl->j_commit_bh);
+      ret = submit_barrier_buffer(jl->j_commit_bh);
+      if (ret == -EOPNOTSUPP) {
+	  set_buffer_uptodate(jl->j_commit_bh);
+          disable_barrier(s);
+	  barrier = 0;
+      }
+  }
   for (i = 0 ;  i < (jl->j_len + 1) ; i++) {
     bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) +
 	 (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ;
@@ -995,10 +1024,14 @@
   if (atomic_read(&(jl->j_commit_left)) != 1)
     BUG();
 
-  if (buffer_dirty(jl->j_commit_bh))
-    BUG();
-  mark_buffer_dirty(jl->j_commit_bh) ;
-  sync_dirty_buffer(jl->j_commit_bh) ;
+  if (!barrier) {
+      if (buffer_dirty(jl->j_commit_bh))
+	BUG();
+      mark_buffer_dirty(jl->j_commit_bh) ;
+      sync_dirty_buffer(jl->j_commit_bh) ;
+  } else
+      wait_on_buffer(jl->j_commit_bh);
+
   if (!buffer_uptodate(jl->j_commit_bh)) {
     reiserfs_panic(s, "journal-615: buffer write failed\n") ;
   }
@@ -1024,7 +1057,6 @@
   up(&jl->j_commit_lock);
 put_jl:
   put_journal_list(s, jl);
-
   return 0 ;
 }
 
@@ -1099,8 +1131,22 @@
     jh->j_last_flush_trans_id = cpu_to_le32(trans_id) ;
     jh->j_first_unflushed_offset = cpu_to_le32(offset) ;
     jh->j_mount_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_mount_id) ;
-    set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ;
-    sync_dirty_buffer(SB_JOURNAL(p_s_sb)->j_header_bh) ;
+
+    if (reiserfs_barrier_flush(p_s_sb)) {
+	int ret;
+	lock_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
+	ret = submit_barrier_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
+	if (ret == -EOPNOTSUPP) {
+	    set_buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh);
+	    disable_barrier(p_s_sb);
+	    goto sync;
+	}
+	wait_on_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
+    } else {
+sync:
+	set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ;
+	sync_dirty_buffer(SB_JOURNAL(p_s_sb)->j_header_bh) ;
+    }
     if (!buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh)) {
       reiserfs_warning (p_s_sb, "journal-837: IO error during journal replay");
       return -EIO ;
@@ -1544,14 +1590,18 @@
     unsigned long cur_len;
     int ret;
     int i;
+    int limit = 256;
     struct reiserfs_journal_list *tjl;
     struct reiserfs_journal_list *flush_jl;
     unsigned long trans_id;
 
     flush_jl = tjl = jl;
 
-    /* flush for 256 transactions or 256 blocks, whichever comes first */
-    for(i = 0 ; i < 256 && len < 256 ; i++) {
+    /* in data logging mode, try harder to flush a lot of blocks */
+    if (reiserfs_data_log(s))
+	limit = 1024;
+    /* flush for 256 transactions or limit blocks, whichever comes first */
+    for(i = 0 ; i < 256 && len < limit ; i++) {
 	if (atomic_read(&tjl->j_commit_left) ||
 	    tjl->j_trans_id < jl->j_trans_id) {
 	    break;
@@ -3181,11 +3231,16 @@
   REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
 }
 
-static void __commit_trans_jl(struct inode *inode, unsigned long id,
+/*
+ * returns -1 on error, 0 if no commits/barriers were done and 1
+ * if a transaction was actually committed and the barrier was done
+ */
+static int __commit_trans_jl(struct inode *inode, unsigned long id,
                                  struct reiserfs_journal_list *jl)
 {
     struct reiserfs_transaction_handle th ;
     struct super_block *sb = inode->i_sb ;
+    int ret = 0;
 
     /* is it from the current transaction, or from an unknown transaction? */
     if (id == SB_JOURNAL(sb)->j_trans_id) {
@@ -3207,6 +3262,7 @@
 	}
 
 	journal_end_sync(&th, sb, 1) ;
+	ret = 1;
 
     } else {
 	/* this gets tricky, we have to make sure the journal list in
@@ -3215,13 +3271,21 @@
 	 */
 flush_commit_only:
 	if (journal_list_still_alive(inode->i_sb, id)) {
+	    /*
+	     * we only set ret to 1 when we know for sure
+	     * the barrier hasn't been started yet on the commit
+	     * block.
+	     */
+	    if (atomic_read(&jl->j_commit_left) > 1)
+	        ret = 1;
 	    flush_commit_list(sb, jl, 1) ;
 	}
     }
     /* otherwise the list is gone, and long since committed */
+    return ret;
 }
 
-void reiserfs_commit_for_inode(struct inode *inode) {
+int reiserfs_commit_for_inode(struct inode *inode) {
     unsigned long id = REISERFS_I(inode)->i_trans_id;
     struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl;
 
@@ -3234,7 +3298,7 @@
 	/* jl will be updated in __commit_trans_jl */
     }
 
-    __commit_trans_jl(inode, id, jl);
+   return __commit_trans_jl(inode, id, jl);
 }
 
 void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb, 
@@ -3482,10 +3546,16 @@
     /* copy all the real blocks into log area.  dirty log blocks */
     if (test_bit(BH_JDirty, &cn->bh->b_state)) {
       struct buffer_head *tmp_bh ;
+      char *addr;
+      struct page *page;
       tmp_bh =  journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
 		       ((cur_write_start + jindex) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
       set_buffer_uptodate(tmp_bh);
-      memcpy(tmp_bh->b_data, cn->bh->b_data, cn->bh->b_size) ;  
+      page = cn->bh->b_page;
+      addr = kmap(page);
+      memcpy(tmp_bh->b_data, addr + offset_in_page(cn->bh->b_data),
+             cn->bh->b_size);
+      kunmap(page);
       mark_buffer_dirty(tmp_bh);
       jindex++ ;
       set_bit(BH_JDirty_wait, &(cn->bh->b_state)) ; 
--- diff/fs/reiserfs/namei.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/reiserfs/namei.c	2004-05-27 18:34:18.000000000 +0100
@@ -1389,8 +1389,9 @@
  * stuff added
  */
 struct inode_operations reiserfs_symlink_inode_operations = {
-    .readlink       = page_readlink,
-    .follow_link    = page_follow_link,
+    .readlink       = generic_readlink,
+    .follow_link    = page_follow_link_light,
+    .put_link       = page_put_link,
     .setattr        = reiserfs_setattr,
     .setxattr       = reiserfs_setxattr,
     .getxattr       = reiserfs_getxattr,
--- diff/fs/reiserfs/stree.c	2004-05-27 13:41:23.000000000 +0100
+++ source/fs/reiserfs/stree.c	2004-05-27 18:34:18.000000000 +0100
@@ -596,26 +596,29 @@
 
 
 
-#ifdef SEARCH_BY_KEY_READA
+#define SEARCH_BY_KEY_READA 16
 
 /* The function is NOT SCHEDULE-SAFE! */
-static void search_by_key_reada (struct super_block * s, int blocknr)
+static void search_by_key_reada (struct super_block * s,
+                                 struct buffer_head **bh,
+				 unsigned long *b, int num)
 {
-    struct buffer_head * bh;
+    int i,j;
   
-    if (blocknr == 0)
-	return;
-
-    bh = sb_getblk (s, blocknr);
-  
-    if (!buffer_uptodate (bh)) {
-	ll_rw_block (READA, 1, &bh);
+    for (i = 0 ; i < num ; i++) {
+	bh[i] = sb_getblk (s, b[i]);
+    }
+    for (j = 0 ; j < i ; j++) {
+	/*
+	 * note, this needs attention if we are getting rid of the BKL
+	 * you have to make sure the prepared bit isn't set on this buffer
+	 */
+	if (!buffer_uptodate(bh[j]))
+	    ll_rw_block(READA, 1, bh + j);
+    	brelse(bh[j]);
     }
-    bh->b_count --;
 }
 
-#endif
-
 /**************************************************************************
  * Algorithm   SearchByKey                                                *
  *             look for item in the Disk S+Tree by its key                *
@@ -657,6 +660,9 @@
     int				n_node_level, n_retval;
     int 			right_neighbor_of_leaf_node;
     int				fs_gen;
+    struct buffer_head *reada_bh[SEARCH_BY_KEY_READA];
+    unsigned long      reada_blocks[SEARCH_BY_KEY_READA];
+    int reada_count = 0;
 
 #ifdef CONFIG_REISERFS_CHECK
     int n_repeat_counter = 0;
@@ -691,19 +697,25 @@
 	p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length);
 	fs_gen = get_generation (p_s_sb);
 
-#ifdef SEARCH_BY_KEY_READA
-	/* schedule read of right neighbor */
-	search_by_key_reada (p_s_sb, right_neighbor_of_leaf_node);
-#endif
-
 	/* Read the next tree node, and set the last element in the path to
            have a pointer to it. */
-	if ( ! (p_s_bh = p_s_last_element->pe_buffer =
-		sb_bread(p_s_sb, n_block_number)) ) {
+	if ((p_s_bh = p_s_last_element->pe_buffer =
+	     sb_getblk(p_s_sb, n_block_number)) ) {
+	    if (!buffer_uptodate(p_s_bh) && reada_count > 1) {
+		search_by_key_reada (p_s_sb, reada_bh,
+		                     reada_blocks, reada_count);
+	    }
+	    ll_rw_block(READ, 1, &p_s_bh);
+	    wait_on_buffer(p_s_bh);
+	    if (!buffer_uptodate(p_s_bh))
+	        goto io_error;
+	} else {
+io_error:
 	    p_s_search_path->path_length --;
 	    pathrelse(p_s_search_path);
 	    return IO_ERROR;
 	}
+	reada_count = 0;
 	if (expected_level == -1)
 		expected_level = SB_TREE_HEIGHT (p_s_sb);
 	expected_level --;
@@ -784,11 +796,36 @@
 	   position in the node. */
 	n_block_number = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position);
 
-#ifdef SEARCH_BY_KEY_READA
-	/* if we are going to read leaf node, then calculate its right neighbor if possible */
-	if (n_node_level == DISK_LEAF_NODE_LEVEL + 1 && p_s_last_element->pe_position < B_NR_ITEMS (p_s_bh))
-	    right_neighbor_of_leaf_node = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position + 1);
-#endif
+	/* if we are going to read leaf nodes, try for read ahead as well */
+	if ((p_s_search_path->reada & PATH_READA) &&
+	    n_node_level == DISK_LEAF_NODE_LEVEL + 1)
+	{
+	    int pos = p_s_last_element->pe_position;
+	    int limit = B_NR_ITEMS(p_s_bh);
+	    struct key *le_key;
+
+	    if (p_s_search_path->reada & PATH_READA_BACK)
+		limit = 0;
+	    while(reada_count < SEARCH_BY_KEY_READA) {
+		if (pos == limit)
+		    break;
+	        reada_blocks[reada_count++] = B_N_CHILD_NUM(p_s_bh, pos);
+		if (p_s_search_path->reada & PATH_READA_BACK)
+		    pos--;
+		else
+		    pos++;
+
+		/*
+		 * check to make sure we're in the same object
+		 */
+		le_key = B_N_PDELIM_KEY(p_s_bh, pos);
+		if (le32_to_cpu(le_key->k_objectid) !=
+		    p_s_key->on_disk_key.k_objectid)
+		{
+		    break;
+		}
+	    }
+        }
     }
 }
 
@@ -1458,6 +1495,41 @@
     reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
 }
 
+static void
+unmap_buffers(struct page *page, loff_t pos) {
+    struct buffer_head *bh ;
+    struct buffer_head *head ;
+    struct buffer_head *next ;
+    unsigned long tail_index ;
+    unsigned long cur_index ;
+
+    if (page) {
+	if (page_has_buffers(page)) {
+	    tail_index = pos & (PAGE_CACHE_SIZE - 1) ;
+	    cur_index = 0 ;
+	    head = page_buffers(page) ;
+	    bh = head ;
+	    do {
+		next = bh->b_this_page ;
+
+		/* we want to unmap the buffers that contain the tail, and
+		** all the buffers after it (since the tail must be at the
+		** end of the file).  We don't want to unmap file data
+		** before the tail, since it might be dirty and waiting to
+		** reach disk
+		*/
+		cur_index += bh->b_size ;
+		if (cur_index > tail_index) {
+		    reiserfs_unmap_buffer(bh) ;
+		}
+		bh = next ;
+	    } while (bh != head) ;
+	    if ( PAGE_SIZE == bh->b_size ) {
+		clear_page_dirty(page);
+	    }
+	}
+    }
+}
 
 static int maybe_indirect_to_direct (struct reiserfs_transaction_handle *th, 
 			      struct inode * p_s_inode,
@@ -1550,7 +1622,7 @@
     char                c_mode;            /* Mode of the balance. */
     int retval2 = -1;
     int quota_cut_bytes;
-    
+    loff_t tail_pos = 0;
     
     init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);
 
@@ -1590,6 +1662,7 @@
       	    set_cpu_key_k_type (p_s_item_key, TYPE_INDIRECT);
 	    p_s_item_key->key_length = 4;
 	    n_new_file_size -= (n_new_file_size & (p_s_sb->s_blocksize - 1));
+	    tail_pos = n_new_file_size;
 	    set_cpu_key_k_offset (p_s_item_key, n_new_file_size + 1);
 	    if ( search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND ){
 		print_block (PATH_PLAST_BUFFER (p_s_path), 3, PATH_LAST_POSITION (p_s_path) - 1, PATH_LAST_POSITION (p_s_path) + 1);
@@ -1687,9 +1760,10 @@
     if ( n_is_inode_locked ) {
 	/* we've done an indirect->direct conversion.  when the data block
 	** was freed, it was removed from the list of blocks that must
-	** be flushed before the transaction commits, so we don't need to
-	** deal with it here.
+	** be flushed before the transaction commits, make sure to
+	** unmap and invalidate it
 	*/
+	unmap_buffers(page, tail_pos);
 	REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ;
     }
 #ifdef REISERQUOTA_DEBUG
@@ -1778,6 +1852,12 @@
            space, this file would have this file size */
 	n_file_size = offset + bytes - 1;
     }
+    /*
+     * are we doing a full truncate or delete, if so
+     * kick in the reada code
+     */
+    if (n_new_file_size == 0)
+        s_search_path.reada = PATH_READA | PATH_READA_BACK;
 
     if ( n_file_size == 0 || n_file_size < n_new_file_size ) {
 	goto update_and_out ;
--- diff/fs/reiserfs/super.c	2004-05-27 13:41:24.000000000 +0100
+++ source/fs/reiserfs/super.c	2004-05-27 18:34:18.000000000 +0100
@@ -492,7 +492,6 @@
     REISERFS_I(inode)->i_acl_default = NULL;
 }
 
-
 struct super_operations reiserfs_sops = 
 {
   .alloc_inode = reiserfs_alloc_inode,
@@ -550,6 +549,13 @@
     {NULL, 0}
 };
 
+/* possible values for -o barrier= */
+static const arg_desc_t barrier_mode[] = {
+    {"none", 1<<REISERFS_BARRIER_NONE, 1<<REISERFS_BARRIER_FLUSH},
+    {"flush", 1<<REISERFS_BARRIER_FLUSH, 1<<REISERFS_BARRIER_NONE},
+    {NULL, 0}
+};
+
 /* possible values for "-o block-allocator=" and bits which are to be set in
    s_mount_opt of reiserfs specific part of in-core super block */
 static const arg_desc_t balloc[] = {
@@ -651,7 +657,7 @@
 	reiserfs_warning (s, "head of option \"%s\" is only correct", opt->option_name);
 	return -1;
     }
-	
+
     /* move to the argument, or to next option if argument is not required */
     p ++;
     
@@ -711,6 +717,7 @@
 	{"replayonly", 0, 0, 1<<REPLAYONLY, 0},
 	{"block-allocator", 'a', balloc, 0, 0},
 	{"data", 'd', logging_mode, 0, 0},
+	{"barrier", 'b', barrier_mode, 0, 0},
 	{"resize", 'r', 0, 0, 0},
 	{"jdev", 'j', 0, 0, 0},
 	{"nolargeio", 'w', 0, 0, 0},
@@ -810,6 +817,23 @@
     }
 }
 
+static void handle_barrier_mode(struct super_block *s, unsigned long bits) {
+    int flush = (1 << REISERFS_BARRIER_FLUSH);
+    int none = (1 << REISERFS_BARRIER_NONE);
+    int all_barrier = flush | none;
+
+    if (bits & all_barrier) {
+        REISERFS_SB(s)->s_mount_opt &= ~all_barrier;
+	if (bits & flush) {
+	    REISERFS_SB(s)->s_mount_opt |= flush;
+	    printk("reiserfs: enabling write barrier flush mode\n");
+	} else if (bits & none) {
+	    REISERFS_SB(s)->s_mount_opt |= none;
+	    printk("reiserfs: write barriers turned off\n");
+	}
+   }
+}
+
 static void handle_attrs( struct super_block *s )
 {
 	struct reiserfs_super_block * rs;
@@ -854,6 +878,8 @@
   safe_mask |= 1 << REISERFS_ATTRS;
   safe_mask |= 1 << REISERFS_XATTRS_USER;
   safe_mask |= 1 << REISERFS_POSIXACL;
+  safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
+  safe_mask |= 1 << REISERFS_BARRIER_NONE;
 
   /* Update the bitmask, taking care to keep
    * the bits we're not allowed to change here */
@@ -900,6 +926,7 @@
     }
 
     handle_data_mode(s, mount_options);
+    handle_barrier_mode(s, mount_options);
     REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
     s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
     journal_begin(&th, s, 10) ;
@@ -1345,15 +1372,17 @@
     memset (sbi, 0, sizeof (struct reiserfs_sb_info));
     /* Set default values for options: non-aggressive tails */
     REISERFS_SB(s)->s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
-    /* default block allocator option: skip_busy */
-    REISERFS_SB(s)->s_alloc_options.bits = ( 1 << 5);
-    /* If file grew past 4 blocks, start preallocation blocks for it. */
-    REISERFS_SB(s)->s_alloc_options.preallocmin = 4;
+    /* no preallocation minimum, be smart in
+       reiserfs_file_write instead */
+    REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
     /* Preallocate by 16 blocks (17-1) at once */
     REISERFS_SB(s)->s_alloc_options.preallocsize = 17;
     /* Initialize the rwsem for xattr dir */
     init_rwsem(&REISERFS_SB(s)->xattr_dir_sem);
 
+    /* setup default block allocator options */
+    reiserfs_init_alloc_options(s);
+
     jdev_name = NULL;
     if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) {
 	goto error;
@@ -1411,6 +1440,9 @@
     } else {
         reiserfs_info (s, "using writeback data mode\n");
     }
+    if (reiserfs_barrier_flush(s)) {
+    	printk("reiserfs: using flush barriers\n");
+    }
 
     // set_device_ro(s->s_dev, 1) ;
     if( journal_init(s, jdev_name, old_format, commit_max_age) ) {
--- diff/fs/reiserfs/tail_conversion.c	2004-05-27 13:41:24.000000000 +0100
+++ source/fs/reiserfs/tail_conversion.c	2004-05-27 18:34:18.000000000 +0100
@@ -162,42 +162,6 @@
     unlock_buffer(bh) ;
 }
 
-static void
-unmap_buffers(struct page *page, loff_t pos) {
-  struct buffer_head *bh ;
-  struct buffer_head *head ;
-  struct buffer_head *next ;
-  unsigned long tail_index ;
-  unsigned long cur_index ;
-
-  if (page) {
-    if (page_has_buffers(page)) {
-      tail_index = pos & (PAGE_CACHE_SIZE - 1) ;
-      cur_index = 0 ;
-      head = page_buffers(page) ;
-      bh = head ;
-      do {
-	next = bh->b_this_page ;
-
-        /* we want to unmap the buffers that contain the tail, and
-        ** all the buffers after it (since the tail must be at the
-        ** end of the file).  We don't want to unmap file data 
-        ** before the tail, since it might be dirty and waiting to 
-        ** reach disk
-        */
-        cur_index += bh->b_size ;
-        if (cur_index > tail_index) {
-          reiserfs_unmap_buffer(bh) ;
-        }
-	bh = next ;
-      } while (bh != head) ;
-      if ( PAGE_SIZE == bh->b_size ) {
-	clear_page_dirty(page);
-      }
-    }
-  } 
-}
-
 /* this first locks inode (neither reads nor sync are permitted),
    reads tail through page cache, insert direct item. When direct item
    inserted successfully inode is left locked. Return value is always
@@ -287,11 +251,6 @@
     }
     kunmap(page) ;
 
-    /* this will invalidate all the buffers in the page after
-    ** pos1
-    */
-    unmap_buffers(page, pos1) ;
-
     /* make sure to get the i_blocks changes from reiserfs_insert_item */
     reiserfs_update_sd(th, p_s_inode);
 
--- diff/fs/reiserfs/xattr.c	2004-05-27 13:41:24.000000000 +0100
+++ source/fs/reiserfs/xattr.c	2004-05-27 18:34:18.000000000 +0100
@@ -1370,13 +1370,15 @@
 		if (!(mode & S_IRWXG))
 			goto check_groups;
 
-                reiserfs_read_lock_xattr_i (inode);
-                if (need_lock)
+                if (need_lock) {
+		    reiserfs_read_lock_xattr_i (inode);
                     reiserfs_read_lock_xattrs (inode->i_sb);
+		}
                 acl = reiserfs_get_acl (inode, ACL_TYPE_ACCESS);
-                if (need_lock)
+                if (need_lock) {
                     reiserfs_read_unlock_xattrs (inode->i_sb);
-                reiserfs_read_unlock_xattr_i (inode);
+		    reiserfs_read_unlock_xattr_i (inode);
+		}
                 if (IS_ERR (acl)) {
                     if (PTR_ERR (acl) == -ENODATA)
                         goto check_groups;
--- diff/fs/select.c	2004-05-19 22:12:24.000000000 +0100
+++ source/fs/select.c	2004-05-27 18:34:18.000000000 +0100
@@ -291,8 +291,6 @@
  * Update: ERESTARTSYS breaks at least the xview clock binary, so
  * I'm trying ERESTARTNOHAND which restart only when you want to.
  */
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
 asmlinkage long
 sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp)
@@ -315,9 +313,11 @@
 		if (sec < 0 || usec < 0)
 			goto out_nofds;
 
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+		if ((unsigned long) sec < (MAX_SCHEDULE_TIMEOUT-1) / HZ - 1) {
 			timeout = ROUND_UP(usec, 1000000/HZ);
 			timeout += sec * (unsigned long) HZ;
+		} else {
+			timeout = MAX_SCHEDULE_TIMEOUT-1;
 		}
 	}
 
@@ -469,11 +469,17 @@
 		return -EINVAL;
 
 	if (timeout) {
-		/* Careful about overflow in the intermediate values */
-		if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ)
-			timeout = (unsigned long)(timeout*HZ+999)/1000+1;
-		else /* Negative or overflow */
+                if (timeout < 0) {
 			timeout = MAX_SCHEDULE_TIMEOUT;
+		} else {
+			/* Careful about overflow in the intermediate values */
+			long seconds = timeout/1000;
+			timeout = ((timeout - 1000*seconds)*HZ + 999)/1000 + 1;
+			if (seconds <= (MAX_SCHEDULE_TIMEOUT-2) / HZ - 1)
+				timeout += seconds*HZ;
+			else
+				timeout = MAX_SCHEDULE_TIMEOUT-1;
+		}
 	}
 
 	poll_initwait(&table);
--- diff/fs/smbfs/proto.h	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/smbfs/proto.h	2004-05-27 18:34:18.000000000 +0100
@@ -87,7 +87,5 @@
 extern int smb_request_send_server(struct smb_sb_info *server);
 extern int smb_request_recv(struct smb_sb_info *server);
 /* symlink.c */
-extern int smb_read_link(struct dentry *dentry, char *buffer, int len);
 extern int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname);
-extern int smb_follow_link(struct dentry *dentry, struct nameidata *nd);
 extern struct inode_operations smb_link_inode_operations;
--- diff/fs/smbfs/symlink.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/smbfs/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -26,19 +26,6 @@
 #include "smb_debug.h"
 #include "proto.h"
 
-int smb_read_link(struct dentry *dentry, char *buffer, int len)
-{
-	char link[256];		/* FIXME: pain ... */
-	int r;
-	DEBUG1("read link buffer len = %d\n", len);
-
-	r = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
-			       sizeof(link) - 1);
-	if (r < 0)
-		return -ENOENT;
-	return vfs_readlink(dentry, buffer, len, link);
-}
-
 int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname)
 {
 	DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry));
@@ -46,24 +33,37 @@
 	return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname);
 }
 
-int smb_follow_link(struct dentry *dentry, struct nameidata *nd)
+static int smb_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char link[256];		/* FIXME: pain ... */
-	int len;
+	char *link = __getname();
 	DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry));
 
-	len = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
-				 sizeof(link) - 1);
-	if(len < 0)
-		return -ENOENT;
-
-	link[len] = 0;
-	return vfs_follow_link(nd, link);
+	if (!link) {
+		link = ERR_PTR(-ENOMEM);
+	} else {
+		int len = smb_proc_read_link(server_from_dentry(dentry),
+						dentry, link, PATH_MAX - 1);
+		if (len < 0) {
+			kfree(link);
+			link = ERR_PTR(len);
+		} else {
+			link[len] = 0;
+		}
+	}
+	nd_set_link(nd, link);
+	return 0;
 }
 
+static void smb_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *s = nd_get_link(nd);
+	if (!IS_ERR(s))
+		putname(s);
+}
 
 struct inode_operations smb_link_inode_operations =
 {
-	.readlink	= smb_read_link,
+	.readlink	= generic_readlink,
 	.follow_link	= smb_follow_link,
+	.put_link	= smb_put_link,
 };
--- diff/fs/super.c	2004-05-27 13:41:24.000000000 +0100
+++ source/fs/super.c	2004-05-27 18:34:18.000000000 +0100
@@ -68,6 +68,7 @@
 		INIT_LIST_HEAD(&s->s_files);
 		INIT_LIST_HEAD(&s->s_instances);
 		INIT_HLIST_HEAD(&s->s_anon);
+		INIT_LIST_HEAD(&s->s_inodes);
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
 		down_write(&s->s_umount);
@@ -569,14 +570,19 @@
 int set_anon_super(struct super_block *s, void *data)
 {
 	int dev;
+	int error;
 
-	spin_lock(&unnamed_dev_lock);
-	if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0) {
-		spin_unlock(&unnamed_dev_lock);
+ retry:
+	if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0)
 		return -ENOMEM;
-	}
-	dev = idr_get_new(&unnamed_dev_idr, NULL);
+	spin_lock(&unnamed_dev_lock);
+	error = idr_get_new(&unnamed_dev_idr, NULL, &dev);
 	spin_unlock(&unnamed_dev_lock);
+	if (error == -EAGAIN)
+		/* We raced and lost with another CPU. */
+		goto retry;
+	else if (error)
+		return -EAGAIN;
 
 	if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
 		spin_lock(&unnamed_dev_lock);
--- diff/fs/sysfs/bin.c	2004-05-27 13:41:24.000000000 +0100
+++ source/fs/sysfs/bin.c	2004-05-27 18:34:18.000000000 +0100
@@ -17,8 +17,10 @@
 static int
 fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
 {
-	struct bin_attribute * attr = dentry->d_fsdata;
-	struct kobject * kobj = dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * attr_sd = dentry->d_fsdata;
+	struct bin_attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 
 	return attr->read(kobj, buffer, off, count);
 }
@@ -60,8 +62,10 @@
 static int
 flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
 {
-	struct bin_attribute *attr = dentry->d_fsdata;
-	struct kobject *kobj = dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * attr_sd = dentry->d_fsdata;
+	struct bin_attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 
 	return attr->write(kobj, buffer, offset, count);
 }
@@ -95,7 +99,8 @@
 static int open(struct inode * inode, struct file * file)
 {
 	struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
-	struct bin_attribute * attr = file->f_dentry->d_fsdata;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct bin_attribute * attr = attr_sd->s_element;
 	int error = -EINVAL;
 
 	if (!kobj || !attr)
@@ -130,8 +135,10 @@
 
 static int release(struct inode * inode, struct file * file)
 {
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
-	struct bin_attribute * attr = file->f_dentry->d_fsdata;
+	struct sysfs_dirent * sd = file->f_dentry->d_parent->d_fsdata;
+	struct kobject * kobj = sd->s_element;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct bin_attribute * attr = attr_sd->s_element;
 	u8 * buffer = file->private_data;
 
 	if (kobj) 
@@ -141,7 +148,7 @@
 	return 0;
 }
 
-static struct file_operations bin_fops = {
+struct file_operations bin_fops = {
 	.read		= read,
 	.write		= write,
 	.llseek		= generic_file_llseek,
@@ -158,31 +165,10 @@
 
 int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
 {
-	struct dentry * dentry;
-	struct dentry * parent;
-	int error = 0;
-
-	if (!kobj || !attr)
-		return -EINVAL;
-
-	parent = kobj->dentry;
-
-	down(&parent->d_inode->i_sem);
-	dentry = sysfs_get_dentry(parent,attr->attr.name);
-	if (!IS_ERR(dentry)) {
-		dentry->d_fsdata = (void *)attr;
-		error = sysfs_create(dentry,
-				     (attr->attr.mode & S_IALLUGO) | S_IFREG,
-				     NULL);
-		if (!error) {
-			dentry->d_inode->i_size = attr->size;
-			dentry->d_inode->i_fop = &bin_fops;
-		}
-		dput(dentry);
-	} else
-		error = PTR_ERR(dentry);
-	up(&parent->d_inode->i_sem);
-	return error;
+	if (kobj && kobj->dentry && attr)
+		return sysfs_add_file(kobj->dentry, &attr->attr,
+					SYSFS_KOBJ_BIN_ATTR);
+	return -EINVAL;
 }
 
 
--- diff/fs/sysfs/dir.c	2004-05-27 13:41:24.000000000 +0100
+++ source/fs/sysfs/dir.c	2004-05-27 18:34:18.000000000 +0100
@@ -10,31 +10,183 @@
 #include <linux/kobject.h>
 #include "sysfs.h"
 
+DECLARE_RWSEM(sysfs_rename_sem);
+
+struct inode_operations sysfs_dir_inode_operations = {
+	.lookup		= sysfs_lookup,
+};
+
+struct file_operations sysfs_dir_operations = {
+	.open		= sysfs_dir_open,
+	.release	= sysfs_dir_close,
+	.llseek		= sysfs_dir_lseek,
+	.read		= generic_read_dir,
+	.readdir	= sysfs_readdir,
+};
+
+static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
+{
+	struct sysfs_dirent * sd = dentry->d_fsdata;
+
+	if (sd) {
+		BUG_ON(sd->s_dentry != dentry);
+		sd->s_dentry = NULL;
+		sysfs_put(sd);
+	}
+	iput(inode);
+}
+
+static struct dentry_operations sysfs_dentry_ops = {
+	.d_iput		= sysfs_d_iput,
+};
+
+const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
+{
+	struct attribute * attr;
+	struct bin_attribute * bin_attr;
+	struct sysfs_symlink  * sl;
+
+	if (!sd || !sd->s_element)
+		BUG();
+
+	switch (sd->s_type) {
+		case SYSFS_KOBJECT:
+		case SYSFS_KOBJ_ATTR_GROUP:
+			/* Always have a dentry so use that */
+			return sd->s_dentry->d_name.name;
+
+		case SYSFS_KOBJ_ATTR:
+			attr = sd->s_element;
+			return attr->name;
+
+		case SYSFS_KOBJ_BIN_ATTR:
+			bin_attr = sd->s_element;
+			return bin_attr->attr.name;
+
+		case SYSFS_KOBJ_LINK:
+			sl = sd->s_element;
+			return sl->link_name;
+	}
+	return NULL;
+}
+
+static int init_file(struct inode * inode)
+{
+	inode->i_size = PAGE_SIZE;
+	inode->i_fop = &sysfs_file_operations;
+	return 0;
+}
+
 static int init_dir(struct inode * inode)
 {
-	inode->i_op = &simple_dir_inode_operations;
-	inode->i_fop = &simple_dir_operations;
+	inode->i_op = &sysfs_dir_inode_operations;
+	inode->i_fop = &sysfs_dir_operations;
 
 	/* directory inodes start off with i_nlink == 2 (for "." entry) */
 	inode->i_nlink++;
 	return 0;
 }
 
+/* attaches attribute's sysfs_dirent to the dentry corresponding to the
+ * attribute file
+ */
+static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry)
+{
+	struct attribute * attr = NULL;
+	struct bin_attribute * bin_attr = NULL;
+        int (* init) (struct inode *) = NULL;
+	int error = 0;
+
+        if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) {
+                bin_attr = sd->s_element;
+                attr = &bin_attr->attr;
+        } else {
+                attr = sd->s_element;
+                init = init_file;
+        }
+
+	error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init);
+	if (error)
+		return error;
+
+        if (bin_attr) {
+		dentry->d_inode->i_size = bin_attr->size;
+		dentry->d_inode->i_fop = &bin_fops;
+	}
+	dentry->d_op = &sysfs_dentry_ops;
+	dentry->d_fsdata = sysfs_get(sd);
+	sd->s_dentry = dentry;
+	d_rehash(dentry);
+
+	return 0;
+}
+
+static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry)
+{
+	int err = 0;
+
+	err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink);
+	if (!err) {
+		dentry->d_op = &sysfs_dentry_ops;
+		dentry->d_fsdata = sysfs_get(sd);
+		sd->s_dentry = dentry;
+		d_rehash(dentry);
+	}
+	return err;
+}
+
+struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
+				struct nameidata *nd)
+{
+	struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * sd;
+	int err = 0;
+
+	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+		if (sd->s_type & SYSFS_NOT_PINNED) {
+			const unsigned char * name = sysfs_get_name(sd);
+
+			if (strcmp(name, dentry->d_name.name))
+				continue;
+
+			if (sd->s_type & SYSFS_KOBJ_LINK)
+				err = sysfs_attach_link(sd, dentry);
+			else
+				err = sysfs_attach_attr(sd, dentry);
+			break;
+		}
+	}
+
+	return ERR_PTR(err);
+}
 
 static int create_dir(struct kobject * k, struct dentry * p,
 		      const char * n, struct dentry ** d)
 {
 	int error;
+	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
 
 	down(&p->d_inode->i_sem);
 	*d = sysfs_get_dentry(p,n);
 	if (!IS_ERR(*d)) {
-		error = sysfs_create(*d,
-					 S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO,
-					 init_dir);
+		error = sysfs_create(*d, mode, init_dir);
 		if (!error) {
-			(*d)->d_fsdata = k;
-			p->d_inode->i_nlink++;
+			struct sysfs_dirent * sd, * parent_sd;
+			parent_sd = p->d_fsdata;
+			sd = sysfs_new_dirent(parent_sd, k,
+						(parent_sd->s_element == k) ?
+						SYSFS_KOBJ_ATTR_GROUP :
+						SYSFS_KOBJECT);
+			if (sd) {
+				(*d)->d_fsdata = sysfs_get(sd);
+				(*d)->d_op = &sysfs_dentry_ops;
+				p->d_inode->i_nlink++;
+				sd->s_element = k;
+				sd->s_dentry = *d;
+				sd->s_mode = mode;
+				d_rehash(*d);
+			} else
+				error = -ENOMEM;
 		}
 		dput(*d);
 	} else
@@ -43,7 +195,6 @@
 	return error;
 }
 
-
 int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
 {
 	return create_dir(k,k->dentry,n,d);
@@ -77,12 +228,16 @@
 	return error;
 }
 
-
 static void remove_dir(struct dentry * d)
 {
 	struct dentry * parent = dget(d->d_parent);
+	struct sysfs_dirent * sd;
+
 	down(&parent->d_inode->i_sem);
 	d_delete(d);
+	sd = d->d_fsdata;
+ 	list_del_init(&sd->s_sibling);
+ 	sysfs_put(d->d_fsdata);
 	if (d->d_inode)
 		simple_rmdir(parent->d_inode,d);
 
@@ -104,14 +259,14 @@
  *	@kobj:	object. 
  *
  *	The only thing special about this is that we remove any files in 
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
+ *	the directory before we remove the directory
  */
 
 void sysfs_remove_dir(struct kobject * kobj)
 {
-	struct list_head * node;
 	struct dentry * dentry = dget(kobj->dentry);
+	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+	struct sysfs_dirent * sd, * tmp;
 
 	if (!dentry)
 		return;
@@ -119,32 +274,13 @@
 	pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
 	down(&dentry->d_inode->i_sem);
 
-	spin_lock(&dcache_lock);
-restart:
-	node = dentry->d_subdirs.next;
-	while (node != &dentry->d_subdirs) {
-		struct dentry * d = list_entry(node,struct dentry,d_child);
-
-		node = node->next;
-		pr_debug(" o %s (%d): ",d->d_name.name,atomic_read(&d->d_count));
-		if (!d_unhashed(d) && (d->d_inode)) {
-			d = dget_locked(d);
-			pr_debug("removing");
-
-			/**
-			 * Unlink and unhash.
-			 */
-			spin_unlock(&dcache_lock);
-			d_delete(d);
-			simple_unlink(dentry->d_inode,d);
-			dput(d);
-			pr_debug(" done\n");
-			spin_lock(&dcache_lock);
-			/* re-acquired dcache_lock, need to restart */
-			goto restart;
-		}
-	}
-	spin_unlock(&dcache_lock);
+	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
+		if (!sd->s_element)
+			continue;
+		list_del_init(&sd->s_sibling);
+		sysfs_drop_dentry(sd, dentry);
+		sysfs_put(sd);
+  	}
 	up(&dentry->d_inode->i_sem);
 
 	remove_dir(dentry);
@@ -165,6 +301,7 @@
 	if (!kobj->parent)
 		return -EINVAL;
 
+	down_write(&sysfs_rename_sem);
 	parent = kobj->parent->dentry;
 
 	down(&parent->d_inode->i_sem);
@@ -173,16 +310,150 @@
 	if (!IS_ERR(new_dentry)) {
   		if (!new_dentry->d_inode) {
 			error = kobject_set_name(kobj,new_name);
-			if (!error)
+			if (!error) {
+				d_add(new_dentry, NULL);
 				d_move(kobj->dentry, new_dentry);
+			}
 		}
 		dput(new_dentry);
 	}
 	up(&parent->d_inode->i_sem);	
+	up_write(&sysfs_rename_sem);
 
 	return error;
 }
 
+int sysfs_dir_open(struct inode *inode, struct file *file)
+{
+	struct dentry * dentry = file->f_dentry;
+	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+
+	down(&dentry->d_inode->i_sem);
+	file->private_data = sysfs_new_dirent(parent_sd, NULL, 0);
+	up(&dentry->d_inode->i_sem);
+
+	return file->private_data ? 0 : -ENOMEM;
+
+}
+
+int sysfs_dir_close(struct inode *inode, struct file *file)
+{
+	struct dentry * dentry = file->f_dentry;
+	struct sysfs_dirent * cursor = file->private_data;
+
+	down(&dentry->d_inode->i_sem);
+	list_del_init(&cursor->s_sibling);
+	up(&dentry->d_inode->i_sem);
+	sysfs_put(file->private_data);
+
+	return 0;
+}
+
+/* Relationship between s_mode and the DT_xxx types */
+static inline unsigned char dt_type(struct sysfs_dirent *sd)
+{
+	return (sd->s_mode >> 12) & 15;
+}
+
+int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+	struct dentry *dentry = filp->f_dentry;
+	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+	struct sysfs_dirent *cursor = filp->private_data;
+	struct list_head *p, *q = &cursor->s_sibling;
+	ino_t ino;
+	int i = filp->f_pos;
+
+	switch (i) {
+		case 0:
+			ino = dentry->d_inode->i_ino;
+			if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+				break;
+			filp->f_pos++;
+			i++;
+			/* fallthrough */
+		case 1:
+			ino = parent_ino(dentry);
+			if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+				break;
+			filp->f_pos++;
+			i++;
+			/* fallthrough */
+		default:
+			if (filp->f_pos == 2) {
+				list_del(q);
+				list_add(q, &parent_sd->s_children);
+			}
+			for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
+				struct sysfs_dirent *next;
+				const char * name;
+				int len;
+
+				next = list_entry(p, struct sysfs_dirent,
+						   s_sibling);
+				if (!next->s_element)
+					continue;
+
+				name = sysfs_get_name(next);
+				len = strlen(name);
+				if (next->s_dentry)
+					ino = next->s_dentry->d_inode->i_ino;
+				else
+					ino = iunique(sysfs_sb, 2);
+
+				if (filldir(dirent, name, len, filp->f_pos, ino,
+						 dt_type(next)) < 0)
+					return 0;
+
+				list_del(q);
+				list_add(q, p);
+				p = q;
+				filp->f_pos++;
+			}
+	}
+	return 0;
+}
+
+loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
+{
+	struct dentry * dentry = file->f_dentry;
+
+	down(&dentry->d_inode->i_sem);
+	switch (origin) {
+		case 1:
+			offset += file->f_pos;
+		case 0:
+			if (offset >= 0)
+				break;
+		default:
+			up(&file->f_dentry->d_inode->i_sem);
+			return -EINVAL;
+	}
+	if (offset != file->f_pos) {
+		file->f_pos = offset;
+		if (file->f_pos >= 2) {
+			struct sysfs_dirent *sd = dentry->d_fsdata;
+			struct sysfs_dirent *cursor = file->private_data;
+			struct list_head *p;
+			loff_t n = file->f_pos - 2;
+
+			list_del(&cursor->s_sibling);
+			p = sd->s_children.next;
+			while (n && p != &sd->s_children) {
+				struct sysfs_dirent *next;
+				next = list_entry(p, struct sysfs_dirent,
+						   s_sibling);
+				if (next->s_element)
+					n--;
+				p = p->next;
+			}
+			list_add_tail(&cursor->s_sibling, p);
+		}
+	}
+	up(&dentry->d_inode->i_sem);
+	return offset;
+}
+
 EXPORT_SYMBOL(sysfs_create_dir);
 EXPORT_SYMBOL(sysfs_remove_dir);
 EXPORT_SYMBOL(sysfs_rename_dir);
--- diff/fs/sysfs/file.c	2004-05-27 13:41:24.000000000 +0100
+++ source/fs/sysfs/file.c	2004-05-27 18:34:18.000000000 +0100
@@ -9,14 +9,6 @@
 
 #include "sysfs.h"
 
-static struct file_operations sysfs_file_operations;
-
-static int init_file(struct inode * inode)
-{
-	inode->i_size = PAGE_SIZE;
-	inode->i_fop = &sysfs_file_operations;
-	return 0;
-}
 
 #define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
 #define to_sattr(a) container_of(a,struct subsys_attribute,attr)
@@ -77,8 +69,10 @@
  */
 static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer)
 {
-	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = file->f_dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 	struct sysfs_ops * ops = buffer->ops;
 	int ret = 0;
 	ssize_t count;
@@ -134,6 +128,9 @@
  *	is in the file's ->d_fsdata. The target object is in the directory's
  *	->d_fsdata.
  *
+ *	It is safe to use ->d_parent->d_fsdata as both dentry and the kobject
+ *	are pinned in ->open().
+ *
  *	We call fill_read_buffer() to allocate and fill the buffer from the
  *	object's show() method exactly once (if the read is happening from
  *	the beginning of the file). That should fill the entire buffer with
@@ -198,8 +195,10 @@
 static int 
 flush_write_buffer(struct file * file, struct sysfs_buffer * buffer, size_t count)
 {
-	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = file->f_dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 	struct sysfs_ops * ops = buffer->ops;
 
 	return ops->store(kobj,attr,buffer->page,count);
@@ -239,7 +238,8 @@
 static int check_perm(struct inode * inode, struct file * file)
 {
 	struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
-	struct attribute * attr = file->f_dentry->d_fsdata;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct attribute * attr = attr_sd->s_element;
 	struct sysfs_buffer * buffer;
 	struct sysfs_ops * ops = NULL;
 	int error = 0;
@@ -320,8 +320,10 @@
 
 static int sysfs_release(struct inode * inode, struct file * filp)
 {
-	struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata;
-	struct attribute * attr = filp->f_dentry->d_fsdata;
+	struct sysfs_dirent * attr_sd = filp->f_dentry->d_fsdata;
+	struct attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = filp->f_dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 	struct sysfs_buffer * buffer = filp->private_data;
 
 	if (kobj) 
@@ -336,7 +338,7 @@
 	return 0;
 }
 
-static struct file_operations sysfs_file_operations = {
+struct file_operations sysfs_file_operations = {
 	.read		= sysfs_read_file,
 	.write		= sysfs_write_file,
 	.llseek		= generic_file_llseek,
@@ -345,23 +347,20 @@
 };
 
 
-int sysfs_add_file(struct dentry * dir, const struct attribute * attr)
+int sysfs_add_file(struct dentry * parent, const struct attribute * attr, int t)
 {
-	struct dentry * dentry;
-	int error;
+	struct sysfs_dirent * sd;
+	struct sysfs_dirent * parent_sd = parent->d_fsdata;
+	int error = 0;
+
+	down(&parent->d_inode->i_sem);
+	sd = sysfs_new_dirent(parent_sd, (void *) attr, t);
+	if (!sd)
+		error =  -ENOMEM;
+	else
+		sd->s_mode =  (attr->mode & S_IALLUGO) | S_IFREG ;
+	up(&parent->d_inode->i_sem);
 
-	down(&dir->d_inode->i_sem);
-	dentry = sysfs_get_dentry(dir,attr->name);
-	if (!IS_ERR(dentry)) {
-		error = sysfs_create(dentry,
-				     (attr->mode & S_IALLUGO) | S_IFREG,
-				     init_file);
-		if (!error)
-			dentry->d_fsdata = (void *)attr;
-		dput(dentry);
-	} else
-		error = PTR_ERR(dentry);
-	up(&dir->d_inode->i_sem);
 	return error;
 }
 
@@ -374,8 +373,8 @@
 
 int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
 {
-	if (kobj && attr)
-		return sysfs_add_file(kobj->dentry,attr);
+	if (kobj && kobj->dentry && attr)
+		return sysfs_add_file(kobj->dentry, attr, SYSFS_KOBJ_ATTR);
 	return -EINVAL;
 }
 
--- diff/fs/sysfs/group.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysfs/group.c	2004-05-27 18:34:18.000000000 +0100
@@ -10,7 +10,7 @@
 
 #include <linux/kobject.h>
 #include <linux/module.h>
-#include <linux/dcache.h>
+#include <linux/fs.h>
 #include <linux/err.h>
 #include "sysfs.h"
 
@@ -31,7 +31,7 @@
 	int error = 0;
 
 	for (attr = grp->attrs; *attr && !error; attr++) {
-		error = sysfs_add_file(dir,*attr);
+		error = sysfs_add_file(dir, *attr, SYSFS_KOBJ_ATTR);
 	}
 	if (error)
 		remove_files(dir,grp);
@@ -70,11 +70,15 @@
 	else
 		dir = dget(kobj->dentry);
 
-	remove_files(dir,grp);
-	if (grp->name)
-		sysfs_remove_subdir(dir);
-	/* release the ref. taken in this routine */
-	dput(dir);
+	if (!IS_ERR(dir)) {
+		if (dir && dir->d_inode) {
+			remove_files(dir,grp);
+			if (grp->name)
+				sysfs_remove_subdir(dir);
+			/* release the ref. taken in this routine */
+			dput(dir);
+		}
+	}
 }
 
 
--- diff/fs/sysfs/inode.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysfs/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -11,6 +11,8 @@
 #include <linux/pagemap.h>
 #include <linux/namei.h>
 #include <linux/backing-dev.h>
+#include "sysfs.h"
+
 extern struct super_block * sysfs_sb;
 
 static struct address_space_operations sysfs_aops = {
@@ -61,7 +63,8 @@
 		error = init(inode);
 	if (!error) {
 		d_instantiate(dentry, inode);
-		dget(dentry); /* Extra count - pin the dentry in core */
+		if (S_ISDIR(mode))
+			dget(dentry);  /* pin only directory dentry in core */
 	} else
 		iput(inode);
  Done:
@@ -83,26 +86,51 @@
 	return lookup_hash(&qstr,parent);
 }
 
-void sysfs_hash_and_remove(struct dentry * dir, const char * name)
+static struct sysfs_dirent * sysfs_find_dirent(struct sysfs_dirent * parent_sd,
+					  const char * name)
 {
-	struct dentry * victim;
+	struct sysfs_dirent *sd;
 
-	down(&dir->d_inode->i_sem);
-	victim = sysfs_get_dentry(dir,name);
-	if (!IS_ERR(victim)) {
-		/* make sure dentry is really there */
-		if (victim->d_inode && 
-		    (victim->d_parent->d_inode == dir->d_inode)) {
-			pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name,
-				 atomic_read(&victim->d_count));
+	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+			if (sd->s_element) {
+				if (!strcmp(sysfs_get_name(sd), name))
+					return sd;
+			}
+	}
+	return NULL;
+}
+
+/* Unhashes the dentry corresponding to given sysfs_dirent
+ * Called with parent inode's i_sem held.
+ */
+void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
+{
+	struct dentry * dentry = sd->s_dentry;
 
-			d_delete(victim);
-			simple_unlink(dir->d_inode,victim);
+	if (dentry) {
+		spin_lock(&dcache_lock);
+		dget_locked(dentry);
+		if (!(d_unhashed(dentry) && dentry->d_inode)) {
+			__d_drop(dentry);
+			spin_unlock(&dcache_lock);
+			simple_unlink(parent->d_inode, dentry);
+		} else {
+			spin_unlock(&dcache_lock);
+			dput(dentry);
 		}
-		/*
-		 * Drop reference from sysfs_get_dentry() above.
-		 */
-		dput(victim);
+	}
+}
+
+void sysfs_hash_and_remove(struct dentry * dir, const char * name)
+{
+	struct sysfs_dirent * sd;
+
+	down(&dir->d_inode->i_sem);
+	sd = sysfs_find_dirent(dir->d_fsdata, name);
+	if (sd) {
+		list_del_init(&sd->s_sibling);
+		sysfs_drop_dentry(sd, dir);
+		sysfs_put(sd);
 	}
 	up(&dir->d_inode->i_sem);
 }
--- diff/fs/sysfs/mount.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysfs/mount.c	2004-05-27 18:34:18.000000000 +0100
@@ -22,6 +22,13 @@
 	.drop_inode	= generic_delete_inode,
 };
 
+struct sysfs_dirent sysfs_root = {
+	.s_sibling	= LIST_HEAD_INIT(sysfs_root.s_sibling),
+	.s_children	= LIST_HEAD_INIT(sysfs_root.s_children),
+	.s_element	= NULL,
+	.s_type		= SYSFS_ROOT,
+};
+
 static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
@@ -35,8 +42,8 @@
 
 	inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
 	if (inode) {
-		inode->i_op = &simple_dir_inode_operations;
-		inode->i_fop = &simple_dir_operations;
+		inode->i_op = &sysfs_dir_inode_operations;
+		inode->i_fop = &sysfs_dir_operations;
 		/* directory inodes start off with i_nlink == 2 (for "." entry) */
 		inode->i_nlink++;	
 	} else {
@@ -50,6 +57,7 @@
 		iput(inode);
 		return -ENOMEM;
 	}
+	root->d_fsdata = &sysfs_root;
 	sb->s_root = root;
 	return 0;
 }
--- diff/fs/sysfs/symlink.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysfs/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -8,27 +8,17 @@
 
 #include "sysfs.h"
 
+static struct inode_operations sysfs_symlink_inode_operations = {
+	.readlink = sysfs_readlink,
+	.follow_link = sysfs_follow_link,
+};
 
-static int init_symlink(struct inode * inode)
+int init_symlink(struct inode * inode)
 {
-	inode->i_op = &page_symlink_inode_operations;
+	inode->i_op = &sysfs_symlink_inode_operations;
 	return 0;
 }
 
-static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
-{
-	int error;
-
-	error = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink);
-	if (!error) {
-		int l = strlen(symname)+1;
-		error = page_symlink(dentry->d_inode, symname, l);
-		if (error)
-			iput(dentry->d_inode);
-	}
-	return error;
-}
-
 static int object_depth(struct kobject * kobj)
 {
 	struct kobject * p = kobj;
@@ -63,6 +53,30 @@
 	}
 }
 
+static int sysfs_add_link(struct sysfs_dirent * parent_sd, char * name,
+			    struct kobject * target)
+{
+	struct sysfs_dirent * sd;
+	struct sysfs_symlink * sl;
+
+	sl = kmalloc(sizeof(*sl), GFP_KERNEL);
+	if (!sl)
+		return -ENOMEM;
+
+	sl->link_name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+	strcpy(sl->link_name, name);
+	sl->target_kobj = kobject_get(target);
+
+	sd = sysfs_new_dirent(parent_sd, sl, SYSFS_KOBJ_LINK);
+	if (sd) {
+		sd->s_mode = S_IFLNK|S_IRWXUGO;
+		return 0;
+	}
+
+	kfree(sl);
+	return -ENOMEM;
+}
+
 /**
  *	sysfs_create_link - create symlink between two objects.
  *	@kobj:	object whose directory we're creating the link in.
@@ -72,39 +86,14 @@
 int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name)
 {
 	struct dentry * dentry = kobj->dentry;
-	struct dentry * d;
 	int error = 0;
-	int size;
-	int depth;
-	char * path;
-	char * s;
 
-	depth = object_depth(kobj);
-	size = object_path_length(target) + depth * 3 - 1;
-	if (size > PATH_MAX)
-		return -ENAMETOOLONG;
-	pr_debug("%s: depth = %d, size = %d\n",__FUNCTION__,depth,size);
-
-	path = kmalloc(size,GFP_KERNEL);
-	if (!path)
-		return -ENOMEM;
-	memset(path,0,size);
-
-	for (s = path; depth--; s += 3)
-		strcpy(s,"../");
-
-	fill_object_path(target,path,size);
-	pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
+	if (!name)
+		return -EINVAL;
 
 	down(&dentry->d_inode->i_sem);
-	d = sysfs_get_dentry(dentry,name);
-	if (!IS_ERR(d))
-		error = sysfs_symlink(dentry->d_inode,d,path);
-	else
-		error = PTR_ERR(d);
-	dput(d);
+	error = sysfs_add_link(dentry->d_fsdata, name, target);
 	up(&dentry->d_inode->i_sem);
-	kfree(path);
 	return error;
 }
 
@@ -120,6 +109,86 @@
 	sysfs_hash_and_remove(kobj->dentry,name);
 }
 
+static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
+				   char *path)
+{
+	char * s;
+	int depth, size;
+
+	depth = object_depth(kobj);
+	size = object_path_length(target) + depth * 3 - 1;
+	if (size > PATH_MAX)
+		return -ENAMETOOLONG;
+
+	pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size);
+
+	for (s = path; depth--; s += 3)
+		strcpy(s,"../");
+
+	fill_object_path(target, path, size);
+	pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
+
+	return 0;
+}
+
+static int sysfs_getlink(struct dentry *dentry, char * path)
+{
+	struct kobject *kobj, *target_kobj;
+	int error = 0;
+
+	kobj = sysfs_get_kobject(dentry->d_parent);
+	if (!kobj)
+		return -EINVAL;
+
+	target_kobj = sysfs_get_kobject(dentry);
+	if (!target_kobj) {
+		kobject_put(kobj);
+		return -EINVAL;
+	}
+
+	down_read(&sysfs_rename_sem);
+	error = sysfs_get_target_path(kobj, target_kobj, path);
+	up_read(&sysfs_rename_sem);
+	
+	kobject_put(kobj);
+	kobject_put(target_kobj);
+	return error;
+
+}
+
+int sysfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+{
+	int error = 0;
+	unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+	if (!page)
+		return -ENOMEM;
+
+	error = sysfs_getlink(dentry, (char *) page);
+	if (!error)
+	        error = vfs_readlink(dentry, buffer, buflen, (char *) page);
+
+	free_page(page);
+
+	return error;
+}
+
+int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	int error = 0;
+	unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+	if (!page)
+		return -ENOMEM;
+
+	error = sysfs_getlink(dentry, (char *) page); 
+	if (!error)
+	        error = vfs_follow_link(nd, (char *) page);
+
+	free_page(page);
+
+	return error;
+}
 
 EXPORT_SYMBOL(sysfs_create_link);
 EXPORT_SYMBOL(sysfs_remove_link);
--- diff/fs/sysfs/sysfs.h	2004-05-27 13:41:24.000000000 +0100
+++ source/fs/sysfs/sysfs.h	2004-05-27 18:34:18.000000000 +0100
@@ -1,26 +1,97 @@
 
+#include <linux/fs.h>
 extern struct vfsmount * sysfs_mount;
+extern struct super_block * sysfs_sb;
 
 extern struct inode * sysfs_new_inode(mode_t mode);
 extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
 
 extern struct dentry * sysfs_get_dentry(struct dentry *, const char *);
+extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
 
-extern int sysfs_add_file(struct dentry * dir, const struct attribute * attr);
 extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
 
 extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
 extern void sysfs_remove_subdir(struct dentry *);
+extern int sysfs_dir_open(struct inode *inode, struct file *file);
+extern int sysfs_dir_close(struct inode *inode, struct file *file);
+extern loff_t sysfs_dir_lseek(struct file *, loff_t, int);
+extern int sysfs_readdir(struct file *, void *, filldir_t);
+extern void sysfs_umount_begin(struct super_block *);
+extern const unsigned char * sysfs_get_name(struct sysfs_dirent *);
+extern struct dentry * sysfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern void sysfs_drop_dentry(struct sysfs_dirent *, struct dentry *);
+extern int sysfs_symlink(struct inode *, struct dentry *, const char *);
+extern int init_symlink(struct inode *);
+
+extern int sysfs_readlink(struct dentry *, char __user *, int );
+extern int sysfs_follow_link(struct dentry *, struct nameidata *);
+extern struct rw_semaphore sysfs_rename_sem;
+extern struct file_operations sysfs_file_operations;
+extern struct file_operations bin_fops;
+extern struct inode_operations sysfs_dir_inode_operations;
+extern struct file_operations sysfs_dir_operations;
+
+struct sysfs_symlink {
+	char * link_name;
+	struct kobject * target_kobj;
+};
 
+static inline
+struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * p, void * e, int t)
+{
+	struct sysfs_dirent * sd;
+
+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	if (!sd)
+		return NULL;
+	memset(sd, 0, sizeof(*sd));
+	atomic_set(&sd->s_count, 1);
+	sd->s_element = e;
+	sd->s_type = t;
+	sd->s_dentry = NULL;
+	INIT_LIST_HEAD(&sd->s_children);
+	list_add(&sd->s_sibling, &p->s_children);
+
+	return sd;
+}
+
+static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
+{
+	if (sd) {
+		WARN_ON(!atomic_read(&sd->s_count));
+		atomic_inc(&sd->s_count);
+	}
+	return sd;
+}
+
+static inline void sysfs_put(struct sysfs_dirent * sd)
+{
+	if (atomic_dec_and_test(&sd->s_count)) {
+		if (sd->s_type & SYSFS_KOBJ_LINK) {
+			struct sysfs_symlink * sl = sd->s_element;
+			kfree(sl->link_name);
+			kobject_put(sl->target_kobj);
+			kfree(sl);
+		}
+		kfree(sd);
+	}
+}
 
 static inline struct kobject *sysfs_get_kobject(struct dentry *dentry)
 {
 	struct kobject * kobj = NULL;
 
-	spin_lock(&dentry->d_lock);
-	if (!d_unhashed(dentry))
-		kobj = kobject_get(dentry->d_fsdata);
-	spin_unlock(&dentry->d_lock);
+	spin_lock(&dcache_lock);
+	if (!d_unhashed(dentry)) {
+		struct sysfs_dirent * sd = dentry->d_fsdata;
+		if (sd->s_type & SYSFS_KOBJ_LINK) {
+			struct sysfs_symlink * sl = sd->s_element;
+			kobj = kobject_get(sl->target_kobj);
+		} else
+			kobj = kobject_get(sd->s_element);
+	}
+	spin_unlock(&dcache_lock);
 
 	return kobj;
 }
--- diff/fs/sysv/inode.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysv/inode.c	2004-05-27 18:34:18.000000000 +0100
@@ -142,8 +142,9 @@
 }
 
 static struct inode_operations sysv_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.getattr	= sysv_getattr,
 };
 
--- diff/fs/sysv/symlink.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysv/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -7,19 +7,13 @@
 
 #include "sysv.h"
 
-static int sysv_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
-	return vfs_readlink(dentry, buffer, buflen, s);
-}
-
 static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
-	return vfs_follow_link(nd, s);
+	nd_set_link(nd, (char *)SYSV_I(dentry->d_inode)->i_data);
+	return 0;
 }
 
 struct inode_operations sysv_fast_symlink_inode_operations = {
-	.readlink	= sysv_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= sysv_follow_link,
 };
--- diff/fs/udf/namei.c	2004-05-19 22:12:32.000000000 +0100
+++ source/fs/udf/namei.c	2004-05-27 18:34:18.000000000 +0100
@@ -154,8 +154,8 @@
 {
 	struct fileIdentDesc *fi=NULL;
 	loff_t f_pos;
-	int block, namelen;
-	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
+	int block, flen;
+	char fname[UDF_NAME_LEN];
 	char *nameptr;
 	uint8_t lfi;
 	uint16_t liu;
@@ -167,9 +167,6 @@
 	if (!dir)
 		return NULL;
 
-	if ( !(namelen = udf_put_filename(dir->i_sb, dentry->d_name.name, name, dentry->d_name.len)))
-		return NULL;
-
 	f_pos = (udf_ext0_offset(dir) >> 2);
 
 	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
@@ -253,10 +250,13 @@
 		if (!lfi)
 			continue;
 
-		if (udf_match(namelen, name, lfi, nameptr))
+		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
 		{
-			udf_release_data(bh);
-			return fi;
+			if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
+			{
+				udf_release_data(bh);
+				return fi;
+			}
 		}
 	}
 	if (fibh->sbh != fibh->ebh)
@@ -353,6 +353,7 @@
 	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
 	int namelen;
 	loff_t f_pos;
+	int flen;
 	char *nameptr;
 	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
 	int nfidlen;
@@ -480,7 +481,8 @@
 		if (!lfi || !dentry)
 			continue;
 
-		if (udf_match(namelen, name, lfi, nameptr))
+		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
+			udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
 		{
 			if (fibh->sbh != fibh->ebh)
 				udf_release_data(fibh->ebh);
--- diff/fs/ufs/symlink.c	2004-05-19 22:12:32.000000000 +0100
+++ source/fs/ufs/symlink.c	2004-05-27 18:34:18.000000000 +0100
@@ -28,19 +28,14 @@
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 
-static int ufs_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	struct ufs_inode_info *p = UFS_I(dentry->d_inode);
-	return vfs_readlink(dentry, buffer, buflen, (char*)p->i_u1.i_symlink);
-}
-
 static int ufs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct ufs_inode_info *p = UFS_I(dentry->d_inode);
-	return vfs_follow_link(nd, (char*)p->i_u1.i_symlink);
+	nd_set_link(nd, (char*)p->i_u1.i_symlink);
+	return 0;
 }
 
 struct inode_operations ufs_fast_symlink_inode_operations = {
-	.readlink	= ufs_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= ufs_follow_link,
 };
--- diff/fs/xfs/Makefile	2004-05-19 22:12:32.000000000 +0100
+++ source/fs/xfs/Makefile	2004-05-27 18:34:18.000000000 +0100
@@ -142,7 +142,6 @@
 xfs-y				+= $(addprefix support/, \
 				   debug.o \
 				   move.o \
-				   qsort.o \
 				   uuid.o)
 
 xfs-$(CONFIG_XFS_TRACE)		+= support/ktrace.o
--- diff/fs/xfs/linux/xfs_iops.c	2004-05-19 22:12:33.000000000 +0100
+++ source/fs/xfs/linux/xfs_iops.c	2004-05-27 18:34:18.000000000 +0100
@@ -419,13 +419,16 @@
 	ASSERT(nd);
 
 	link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL);
-	if (!link)
-		return -ENOMEM;
+	if (!link) {
+		nd_set_link(nd, ERR_PTR(-ENOMEM));
+		return 0;
+	}
 
 	uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL);
 	if (!uio) {
 		kfree(link);
-		return -ENOMEM;
+		nd_set_link(nd, ERR_PTR(-ENOMEM));
+		return 0;
 	}
 
 	vp = LINVFS_GET_VP(dentry->d_inode);
@@ -441,18 +444,22 @@
 
 	VOP_READLINK(vp, uio, 0, NULL, error);
 	if (error) {
-		kfree(uio);
 		kfree(link);
-		return -error;
+		link = ERR_PTR(-error);
+	} else {
+		link[MAXNAMELEN - uio->uio_resid] = '\0';
 	}
-
-	link[MAXNAMELEN - uio->uio_resid] = '\0';
 	kfree(uio);
 
-	/* vfs_follow_link returns (-) errors */
-	error = vfs_follow_link(nd, link);
-	kfree(link);
-	return error;
+	nd_set_link(nd, link);
+	return 0;
+}
+
+static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *s = nd_get_link(nd);
+	if (!IS_ERR(s))
+		kfree(s);
 }
 
 #ifdef CONFIG_XFS_POSIX_ACL
@@ -698,6 +705,7 @@
 struct inode_operations linvfs_symlink_inode_operations = {
 	.readlink		= linvfs_readlink,
 	.follow_link		= linvfs_follow_link,
+	.put_link		= linvfs_put_link,
 	.permission		= linvfs_permission,
 	.getattr		= linvfs_getattr,
 	.setattr		= linvfs_setattr,
--- diff/fs/xfs/linux/xfs_linux.h	2004-05-19 22:12:33.000000000 +0100
+++ source/fs/xfs/linux/xfs_linux.h	2004-05-27 18:34:18.000000000 +0100
@@ -64,7 +64,6 @@
 #include <sema.h>
 #include <time.h>
 
-#include <support/qsort.h>
 #include <support/ktrace.h>
 #include <support/debug.h>
 #include <support/move.h>
--- diff/fs/xfs/support/qsort.c	2004-05-19 22:12:33.000000000 +0100
+++ source/fs/xfs/support/qsort.c	2004-05-27 18:34:18.000000000 +0100
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) { 		\
-	long i = (n) / sizeof (TYPE); 			\
-	register TYPE *pi = (TYPE *) (parmi); 		\
-	register TYPE *pj = (TYPE *) (parmj); 		\
-	do { 						\
-		register TYPE	t = *pi;		\
-		*pi++ = *pj;				\
-		*pj++ = t;				\
-        } while (--i > 0);				\
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
-	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static __inline void
-swapfunc(char *a, char *b, int n, int swaptype)
-{
-	if (swaptype <= 1) 
-		swapcode(long, a, b, n)
-	else
-		swapcode(char, a, b, n)
-}
-
-#define swap(a, b)					\
-	if (swaptype == 0) {				\
-		long t = *(long *)(a);			\
-		*(long *)(a) = *(long *)(b);		\
-		*(long *)(b) = t;			\
-	} else						\
-		swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-static __inline char *
-med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
-{
-	return cmp(a, b) < 0 ?
-	       (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
-              :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
-}
-
-void
-qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *))
-{
-	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
-	int d, r, swaptype, swap_cnt;
-	register char *a = aa;
-
-loop:	SWAPINIT(a, es);
-	swap_cnt = 0;
-	if (n < 7) {
-		for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
-			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
-			     pl -= es)
-				swap(pl, pl - es);
-		return;
-	}
-	pm = (char *)a + (n / 2) * es;
-	if (n > 7) {
-		pl = (char *)a;
-		pn = (char *)a + (n - 1) * es;
-		if (n > 40) {
-			d = (n / 8) * es;
-			pl = med3(pl, pl + d, pl + 2 * d, cmp);
-			pm = med3(pm - d, pm, pm + d, cmp);
-			pn = med3(pn - 2 * d, pn - d, pn, cmp);
-		}
-		pm = med3(pl, pm, pn, cmp);
-	}
-	swap(a, pm);
-	pa = pb = (char *)a + es;
-
-	pc = pd = (char *)a + (n - 1) * es;
-	for (;;) {
-		while (pb <= pc && (r = cmp(pb, a)) <= 0) {
-			if (r == 0) {
-				swap_cnt = 1;
-				swap(pa, pb);
-				pa += es;
-			}
-			pb += es;
-		}
-		while (pb <= pc && (r = cmp(pc, a)) >= 0) {
-			if (r == 0) {
-				swap_cnt = 1;
-				swap(pc, pd);
-				pd -= es;
-			}
-			pc -= es;
-		}
-		if (pb > pc)
-			break;
-		swap(pb, pc);
-		swap_cnt = 1;
-		pb += es;
-		pc -= es;
-	}
-	if (swap_cnt == 0) {  /* Switch to insertion sort */
-		for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
-			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; 
-			     pl -= es)
-				swap(pl, pl - es);
-		return;
-	}
-
-	pn = (char *)a + n * es;
-	r = min(pa - (char *)a, pb - pa);
-	vecswap(a, pb - r, r);
-	r = min((long)(pd - pc), (long)(pn - pd - es));
-	vecswap(pb, pn - r, r);
-	if ((r = pb - pa) > es)
-		qsort(a, r / es, es, cmp);
-	if ((r = pd - pc) > es) { 
-		/* Iterate rather than recurse to save stack space */
-		a = pn - r;
-		n = r / es;
-		goto loop;
-	}
-/*		qsort(pn - r, r / es, es, cmp);*/
-}
--- diff/fs/xfs/support/qsort.h	2004-05-19 22:12:33.000000000 +0100
+++ source/fs/xfs/support/qsort.h	2004-05-27 18:34:18.000000000 +0100
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#ifndef QSORT_H
-#define QSORT_H
-
-extern void qsort (void *const pbase,
-		    size_t total_elems,
-		    size_t size,
-		    int (*cmp)(const void *, const void *));
-
-#endif
--- diff/include/acpi/acpi_drivers.h	2004-05-19 22:12:33.000000000 +0100
+++ source/include/acpi/acpi_drivers.h	2004-05-27 18:34:18.000000000 +0100
@@ -55,7 +55,7 @@
 
 /* ACPI PCI Interrupt Link (pci_link.c) */
 
-int acpi_pci_link_check (void);
+int acpi_irq_penalty_init (void);
 int acpi_pci_link_get_irq (acpi_handle handle, int index, int* edge_level, int* active_high_low);
 
 /* ACPI PCI Interrupt Routing (pci_irq.c) */
--- diff/include/asm-alpha/resource.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-alpha/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -15,9 +15,11 @@
 #define RLIMIT_AS	7		/* address space limit(?) */
 #define RLIMIT_NPROC	8		/* max number of processes */
 #define RLIMIT_MEMLOCK	9		/* max locked-in-memory address space */
-#define RLIMIT_LOCKS   10              /* maximum file locks held */
+#define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.  Fine, it's unsigned, but
@@ -40,7 +42,9 @@
     {LONG_MAX, LONG_MAX},			/* RLIMIT_AS */		\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_NPROC */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_MEMLOCK */	\
-    {LONG_MAX, LONG_MAX},                       /* RLIMIT_LOCKS */      \
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_LOCKS */	\
+    {MAX_SIGPENDING, MAX_SIGPENDING},		/* RLIMIT_SIGPENDING */ \
+    {MQ_BYTES_MAX, MQ_BYTES_MAX},		/* RLIMIT_MSGQUEUE */	\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-alpha/spinlock.h	2004-05-27 13:41:24.000000000 +0100
+++ source/include/asm-alpha/spinlock.h	2004-05-27 18:34:18.000000000 +0100
@@ -6,6 +6,10 @@
 #include <linux/kernel.h>
 #include <asm/current.h>
 
+#ifdef CONFIG_LOCKMETER
+#undef DEBUG_SPINLOCK
+#undef DEBUG_RWLOCK
+#endif
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
@@ -96,9 +100,18 @@
 
 typedef struct {
 	volatile int write_lock:1, read_counter:31;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* need this storage for CPU and lock INDEX ............. */
+	unsigned magic;
+#endif
 } /*__attribute__((aligned(32)))*/ rwlock_t;
 
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#endif
 
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *)(x) != 0)
@@ -170,4 +183,41 @@
 	: "m" (*lock) : "memory");
 }
 
+#ifdef CONFIG_LOCKMETER
+static inline int _raw_write_trylock(rwlock_t *lock)
+{
+	long temp,result;
+
+	__asm__ __volatile__(
+	"	ldl_l %1,%0\n"
+	"	mov $31,%2\n"
+	"	bne %1,1f\n"
+	"	or $31,1,%2\n"
+	"	stl_c %2,%0\n"
+	"1:	mb\n"
+	: "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
+	: "m" (*(volatile int *)lock)
+	);
+
+	return (result);
+}
+
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+	unsigned long temp,result;
+
+	__asm__ __volatile__(
+	"	ldl_l %1,%0\n"
+	"	mov $31,%2\n"
+	"	blbs %1,1f\n"
+	"	subl %1,2,%2\n"
+	"	stl_c %2,%0\n"
+	"1:	mb\n"
+	: "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
+	: "m" (*(volatile int *)lock)
+	);
+	return (result);
+}
+#endif /* CONFIG_LOCKMETER */
+
 #endif /* _ALPHA_SPINLOCK_H */
--- diff/include/asm-alpha/system.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-alpha/system.h	2004-05-27 18:34:18.000000000 +0100
@@ -43,7 +43,6 @@
  */
 #define PARAM			ZERO_PGE
 #define COMMAND_LINE		((char*)(PARAM + 0x0000))
-#define COMMAND_LINE_SIZE	256
 #define INITRD_START		(*(unsigned long *) (PARAM+0x100))
 #define INITRD_SIZE		(*(unsigned long *) (PARAM+0x108))
 
--- diff/include/asm-arm/arch-ixp4xx/uncompress.h	2004-05-27 13:41:24.000000000 +0100
+++ source/include/asm-arm/arch-ixp4xx/uncompress.h	2004-05-27 18:34:18.000000000 +0100
@@ -48,7 +48,7 @@
 	/*
 	 * Coyote only has UART2 connected
 	 */
-	if (__machine_arch_type == MACH_TYPE_ADI_COYOTE)
+	if (machine_is_adi_coyote())
 		uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
 	else
 		uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
--- diff/include/asm-arm/arch-lh7a40x/hardware.h	2004-05-19 22:12:35.000000000 +0100
+++ source/include/asm-arm/arch-lh7a40x/hardware.h	2004-05-27 18:34:18.000000000 +0100
@@ -13,8 +13,6 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#include <asm/mach-types.h>
-
 #define io_p2v(x) (0xf0000000 | (((x) & 0xfff00000) >> 4) | ((x) & 0x0000ffff))
 #define io_v2p(x) (             (((x) & 0x0fff0000) << 4) | ((x) & 0x0000ffff))
 
--- diff/include/asm-arm/arch-omap/hardware.h	2004-05-27 13:41:24.000000000 +0100
+++ source/include/asm-arm/arch-omap/hardware.h	2004-05-27 18:34:18.000000000 +0100
@@ -40,7 +40,6 @@
 #ifndef __ASSEMBLER__
 #include <asm/types.h>
 #endif
-#include <asm/mach-types.h>
 
 /*
  * ----------------------------------------------------------------------------
--- diff/include/asm-arm/arch-omap/uncompress.h	2004-05-27 13:41:24.000000000 +0100
+++ source/include/asm-arm/arch-omap/uncompress.h	2004-05-27 18:34:18.000000000 +0100
@@ -20,7 +20,6 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/serial_reg.h>
-#include <asm/mach-types.h>
 #include <asm/hardware.h>
 #include <asm/arch/serial.h>
 
--- diff/include/asm-arm/arch-pxa/hardware.h	2004-05-27 13:41:24.000000000 +0100
+++ source/include/asm-arm/arch-pxa/hardware.h	2004-05-27 18:34:18.000000000 +0100
@@ -13,9 +13,6 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#include <asm/mach-types.h>
-
-
 /*
  * We requires absolute addresses.
  */
--- diff/include/asm-arm/arch-pxa/lubbock.h	2004-05-19 22:12:36.000000000 +0100
+++ source/include/asm-arm/arch-pxa/lubbock.h	2004-05-27 18:34:18.000000000 +0100
@@ -35,3 +35,6 @@
 #define LUB_IRQ_SET_CLR		__LUB_REG(LUBBOCK_FPGA_PHYS + 0x0d0)
 #define LUB_GP			__LUB_REG(LUBBOCK_FPGA_PHYS + 0x100)
 
+#ifndef __ASSEMBLY__
+extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set);
+#endif
--- diff/include/asm-arm/cacheflush.h	2004-05-27 13:41:25.000000000 +0100
+++ source/include/asm-arm/cacheflush.h	2004-05-27 18:34:18.000000000 +0100
@@ -304,9 +304,9 @@
 }
 
 #define flush_dcache_mmap_lock(mapping) \
-	spin_lock_irq(&(mapping)->tree_lock)
+	write_lock_irq(&(mapping)->tree_lock)
 #define flush_dcache_mmap_unlock(mapping) \
-	spin_unlock_irq(&(mapping)->tree_lock)
+	write_unlock_irq(&(mapping)->tree_lock)
 
 #define flush_icache_user_range(vma,page,addr,len) \
 	flush_dcache_page(page)
--- diff/include/asm-arm/hardware/sa1111.h	2004-05-19 22:12:37.000000000 +0100
+++ source/include/asm-arm/hardware/sa1111.h	2004-05-27 18:34:18.000000000 +0100
@@ -405,22 +405,6 @@
 #define GPIO_C6		(1 << 22)
 #define GPIO_C7		(1 << 23)
 
-#define PA_DDR		__CCREG(0x1000)
-#define PA_DRR		__CCREG(0x1004)
-#define PA_DWR		__CCREG(0x1004)
-#define PA_SDR		__CCREG(0x1008)
-#define PA_SSR		__CCREG(0x100c)
-#define PB_DDR		__CCREG(0x1010)
-#define PB_DRR		__CCREG(0x1014)
-#define PB_DWR		__CCREG(0x1014)
-#define PB_SDR		__CCREG(0x1018)
-#define PB_SSR		__CCREG(0x101c)
-#define PC_DDR		__CCREG(0x1020)
-#define PC_DRR		__CCREG(0x1024)
-#define PC_DWR		__CCREG(0x1024)
-#define PC_SDR		__CCREG(0x1028)
-#define PC_SSR		__CCREG(0x102c)
-
 /*
  * Interrupt Controller
  *
--- diff/include/asm-arm/resource.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-arm/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -40,6 +42,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
+	{ MAX_SIGPENDING, MAX_SIGPENDING},	\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX},		\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-arm/system.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-arm/system.h	2004-05-27 18:34:18.000000000 +0100
@@ -137,22 +137,48 @@
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
 
-#define prepare_to_switch()    do { } while(0)
+#ifdef CONFIG_SMP
+/*
+ * Define our own context switch locking.  This allows us to enable
+ * interrupts over the context switch, otherwise we end up with high
+ * interrupt latency.  The real problem area is switch_mm() which may
+ * do a full cache flush.
+ */
+#define prepare_arch_switch(rq,next)					\
+do {									\
+	spin_lock(&(next)->switch_lock);				\
+	spin_unlock_irq(&(rq)->lock);					\
+} while (0)
+
+#define finish_arch_switch(rq,prev)					\
+	spin_unlock(&(prev)->switch_lock)
+
+#define task_running(rq,p)						\
+	((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
+#else
+/*
+ * Our UP-case is more simple, but we assume knowledge of how
+ * spin_unlock_irq() and friends are implemented.  This avoids
+ * us needlessly decrementing and incrementing the preempt count.
+ */
+#define prepare_arch_switch(rq,next)	local_irq_enable()
+#define finish_arch_switch(rq,prev)	spin_unlock(&(rq)->lock)
+#define task_running(rq,p)		((rq)->curr == (p))
+#endif
 
 /*
  * switch_to(prev, next) should switch from task `prev' to `next'
- * `prev' will never be the same as `next'.
- * The `mb' is to tell GCC not to cache `current' across this call.
+ * `prev' will never be the same as `next'.  schedule() itself
+ * contains the memory barrier to tell GCC not to cache `current'.
  */
 struct thread_info;
 struct task_struct;
 extern struct task_struct *__switch_to(struct task_struct *, struct thread_info *, struct thread_info *);
 
-#define switch_to(prev,next,last)						\
-	do {									\
-		last = __switch_to(prev,prev->thread_info,next->thread_info);	\
-		mb();								\
-	} while (0)
+#define switch_to(prev,next,last)					\
+do {									\
+	last = __switch_to(prev,prev->thread_info,next->thread_info);	\
+} while (0)
 
 /*
  * CPU interrupt mask handling.
--- diff/include/asm-arm/unistd.h	2004-05-27 13:41:25.000000000 +0100
+++ source/include/asm-arm/unistd.h	2004-05-27 18:34:18.000000000 +0100
@@ -454,6 +454,7 @@
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_TIME
 #define __ARCH_WANT_SYS_UTIME
 #define __ARCH_WANT_SYS_SOCKETCALL
--- diff/include/asm-arm26/resource.h	2004-05-19 22:12:38.000000000 +0100
+++ source/include/asm-arm26/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -40,6 +42,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
+	{ MAX_SIGPENDING, MAX_SIGPENDING},	\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX},		\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-arm26/tlb.h	2004-05-19 22:12:38.000000000 +0100
+++ source/include/asm-arm26/tlb.h	2004-05-27 18:34:18.000000000 +0100
@@ -1,6 +1,7 @@
 #ifndef __ASMARM_TLB_H
 #define __ASMARM_TLB_H
 
+#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 /*
--- diff/include/asm-cris/resource.h	2004-05-19 22:12:38.000000000 +0100
+++ source/include/asm-cris/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -15,9 +15,11 @@
 #define RLIMIT_NOFILE	7		/* max number of open files */
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
-#define RLIMIT_LOCKS   10              /* maximum file locks held */
+#define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -38,8 +40,10 @@
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },               \
-        { RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-cris/setup.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-cris/setup.h	2004-05-27 18:34:18.000000000 +0100
@@ -1,3 +1,6 @@
 #ifndef _CRIS_SETUP_H
 #define _CRIS_SETUP_H
+
+#define COMMAND_LINE_SIZE	256
+
 #endif
--- diff/include/asm-generic/pgtable.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/pgtable.h	2004-05-27 18:34:18.000000000 +0100
@@ -2,6 +2,11 @@
 #define _ASM_GENERIC_PGTABLE_H
 
 #ifndef __HAVE_ARCH_PTEP_ESTABLISH
+
+#ifndef ptep_update_dirty_accessed
+#define ptep_update_dirty_accessed(__ptep, __entry, __dirty) set_pte(__ptep, __entry)
+#endif
+
 /*
  * Establish a new mapping:
  *  - flush the old one
@@ -10,9 +15,9 @@
  *
  * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
  */
-#define ptep_establish(__vma, __address, __ptep, __entry)		\
+#define ptep_establish(__vma, __address, __ptep, __entry, __dirty)	\
 do {									\
-	set_pte(__ptep, __entry);					\
+	ptep_update_dirty_accessed(__ptep, __entry, __dirty);		\
 	flush_tlb_page(__vma, __address);				\
 } while (0)
 #endif
--- diff/include/asm-generic/tlb.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/tlb.h	2004-05-27 18:34:18.000000000 +0100
@@ -15,6 +15,7 @@
 
 #include <linux/config.h>
 #include <linux/swap.h>
+#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 /*
@@ -146,4 +147,10 @@
 		__pmd_free_tlb(tlb, pmdp);			\
 	} while (0)
 
+#define tlb_migrate_finish(mm)					\
+	do {							\
+		if (likely(mm))					\
+			flush_tlb_mm(mm);			\
+	} while (0)
+
 #endif /* _ASM_GENERIC__TLB_H */
--- diff/include/asm-h8300/module.h	2004-05-27 13:41:25.000000000 +0100
+++ source/include/asm-h8300/module.h	2004-05-27 18:34:18.000000000 +0100
@@ -8,4 +8,6 @@
 #define Elf_Sym Elf32_Sym
 #define Elf_Ehdr Elf32_Ehdr
 
+#define MODULE_SYMBOL_PREFIX "_"
+
 #endif /* _ASM_H8/300_MODULE_H */
--- diff/include/asm-h8300/resource.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-h8300/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +41,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-h8300/setup.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-h8300/setup.h	2004-05-27 18:34:18.000000000 +0100
@@ -1 +1,6 @@
-/* Nothing do */
+#ifndef __H8300_SETUP_H
+#define __H8300_SETUP_H
+
+#define COMMAND_LINE_SIZE	512
+
+#endif
--- diff/include/asm-i386/bugs.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/bugs.h	2004-05-27 18:34:18.000000000 +0100
@@ -1,11 +1,11 @@
 /*
  *  include/asm-i386/bugs.h
  *
- *  Copyright (C) 1994  Linus Torvalds
+ *  Copyright (C) 1994	Linus Torvalds
  *
  *  Cyrix stuff, June 1998 by:
  *	- Rafael R. Reilova (moved everything from head.S),
- *        <rreilova@ececs.uc.edu>
+ *	  <rreilova@ececs.uc.edu>
  *	- Channing Corn (tests & fixes),
  *	- Andrew D. Balsa (code cleanup).
  *
@@ -25,7 +25,20 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/msr.h>
-
+#ifdef CONFIG_KGDB
+/*
+ * Provied the command line "gdb" initial break
+ */
+int __init kgdb_initial_break(char * str)
+{
+	if (*str == '\0'){
+		breakpoint();
+		return 1;
+	}
+	return 0;
+}
+__setup("gdb",kgdb_initial_break);
+#endif
 static int __init no_halt(char *s)
 {
 	boot_cpu_data.hlt_works_ok = 0;
@@ -140,7 +153,7 @@
 	  : "ecx", "edi" );
 	/* If this fails, it means that any user program may lock the CPU hard. Too bad. */
 	if (res != 12345678) printk( "Buggy.\n" );
-		        else printk( "OK.\n" );
+			else printk( "OK.\n" );
 #endif
 }
 
--- diff/include/asm-i386/dma-mapping.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-i386/dma-mapping.h	2004-05-27 18:34:18.000000000 +0100
@@ -2,6 +2,8 @@
 #define _ASM_I386_DMA_MAPPING_H
 
 #include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
--- diff/include/asm-i386/hpet.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/hpet.h	2004-05-27 18:34:18.000000000 +0100
@@ -57,9 +57,12 @@
 #define HPET_ID_LEGSUP	0x00008000
 #define HPET_ID_NUMBER	0x00001f00
 #define HPET_ID_REV	0x000000ff
+#define	HPET_ID_NUMBER_SHIFT	8
 
 #define HPET_CFG_ENABLE	0x001
 #define HPET_CFG_LEGACY	0x002
+#define	HPET_LEGACY_8254	2
+#define	HPET_LEGACY_RTC		8
 
 #define HPET_TN_ENABLE		0x004
 #define HPET_TN_PERIODIC	0x008
--- diff/include/asm-i386/hw_irq.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/hw_irq.h	2004-05-27 18:34:18.000000000 +0100
@@ -59,7 +59,7 @@
 void print_IO_APIC(void);
 int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
 void send_IPI(int dest, int vector);
-void setup_ioapic_dest(cpumask_t mask);
+void setup_ioapic_dest(void);
 
 extern unsigned long io_apic_irqs;
 
--- diff/include/asm-i386/ide.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-i386/ide.h	2004-05-27 18:34:18.000000000 +0100
@@ -26,9 +26,6 @@
 static __inline__ int ide_default_irq(unsigned long base)
 {
 	switch (base) {
-#ifdef CONFIG_X86_PC9800
-		case 0x640: return 9;
-#endif
 		case 0x1f0: return 14;
 		case 0x170: return 15;
 		case 0x1e8: return 11;
@@ -43,48 +40,17 @@
 static __inline__ unsigned long ide_default_io_base(int index)
 {
 	switch (index) {
-#ifdef CONFIG_X86_PC9800
-		case 0:
-		case 1:	return 0x640;
-#else
 		case 0:	return 0x1f0;
 		case 1:	return 0x170;
 		case 2: return 0x1e8;
 		case 3: return 0x168;
 		case 4: return 0x1e0;
 		case 5: return 0x160;
-#endif
 		default:
 			return 0;
 	}
 }
 
-#ifdef CONFIG_X86_PC9800
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
-	 unsigned long ctrl_port, int *irq)
-{
-	unsigned long reg = data_port;
-	int i;
-
-	unsigned long increment = data_port == 0x640 ? 2 : 1;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += increment;
-	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-	} else if (data_port == 0x640) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = 0x74c;
-	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
-	}
-	if (irq != NULL)
-		*irq = 0;
-	hw->io_ports[IDE_IRQ_OFFSET] = 0;
-}
-#endif
-
 #define IDE_ARCH_OBSOLETE_INIT
 #define ide_default_io_ctl(base)	((base) + 0x206) /* obsolete */
 
--- diff/include/asm-i386/io.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/io.h	2004-05-27 18:34:18.000000000 +0100
@@ -364,4 +364,19 @@
 BUILDIO(w,w,short)
 BUILDIO(l,,int)
 
+static inline u64 readq(void *addr)
+{
+	return readl(addr) | (((u64)readl(addr + 4)) << 32);
+}
+
+static inline void writeq(u64 v, void *addr)
+{
+	u32 v32;
+
+	v32 = v;
+	writel(v32, addr);
+	v32 = v >> 32;
+	writel(v32, addr + 4);
+}
+
 #endif
--- diff/include/asm-i386/mach-bigsmp/mach_apic.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-bigsmp/mach_apic.h	2004-05-27 18:34:18.000000000 +0100
@@ -22,13 +22,21 @@
 }
 
 #define APIC_DFR_VALUE	(APIC_DFR_CLUSTER)
+/* Round robin the irqs amoung the online cpus */
 static inline cpumask_t target_cpus(void)
 { 
-	return cpu_online_map;
+	static unsigned long cpu = NR_CPUS;
+	do {
+		if (cpu >= NR_CPUS)
+			cpu = first_cpu_const(cpu_online_map);
+		else
+			cpu = next_cpu_const(cpu, cpu_online_map);
+	} while (cpu >= NR_CPUS);
+	return mk_cpumask_const(cpumask_of_cpu(cpu));
 }
 #define TARGET_CPUS	(target_cpus())
 
-#define INT_DELIVERY_MODE dest_LowestPrio
+#define INT_DELIVERY_MODE dest_Fixed
 #define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
 
 #define APIC_BROADCAST_ID     (0xff)
@@ -141,36 +149,14 @@
 	return (1);
 }
 
+/* As we are using single CPU as destination, pick only one CPU here */
 static inline unsigned int cpu_mask_to_apicid(cpumask_const_t cpumask)
 {
-	int num_bits_set;
-	int cpus_found = 0;
 	int cpu;
 	int apicid;	
 
-	num_bits_set = cpus_weight_const(cpumask);
-	/* Return id to all */
-	if (num_bits_set == NR_CPUS)
-		return (int) 0xFF;
-	/* 
-	 * The cpus in the mask must all be on the apic cluster.  If are not 
-	 * on the same apicid cluster return default value of TARGET_CPUS. 
-	 */
 	cpu = first_cpu_const(cpumask);
 	apicid = cpu_to_logical_apicid(cpu);
-	while (cpus_found < num_bits_set) {
-		if (cpu_isset_const(cpu, cpumask)) {
-			int new_apicid = cpu_to_logical_apicid(cpu);
-			if (apicid_cluster(apicid) != 
-					apicid_cluster(new_apicid)){
-				printk ("%s: Not a valid mask!\n",__FUNCTION__);
-				return 0xFF;
-			}
-			apicid = apicid | new_apicid;
-			cpus_found++;
-		}
-		cpu++;
-	}
 	return apicid;
 }
 
--- diff/include/asm-i386/mpspec.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/mpspec.h	2004-05-27 18:34:18.000000000 +0100
@@ -33,7 +33,7 @@
 extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
 extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
 extern void mp_config_acpi_legacy_irqs (void);
-extern void mp_parse_prt (void);
+extern void mp_register_gsi (u32 gsi, int edge_level, int active_high_low);
 #endif /*CONFIG_ACPI_BOOT*/
 
 #define PHYSID_ARRAY_SIZE	BITS_TO_LONGS(MAX_APICS)
--- diff/include/asm-i386/param.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-i386/param.h	2004-05-27 18:34:18.000000000 +0100
@@ -18,5 +18,6 @@
 #endif
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
+#define COMMAND_LINE_SIZE 256
 
 #endif
--- diff/include/asm-i386/pgtable.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-i386/pgtable.h	2004-05-27 18:34:18.000000000 +0100
@@ -317,8 +317,18 @@
 /*
  * The i386 doesn't have any external MMU info: the kernel page
  * tables contain all the necessary information.
+ *
+ * Also, we only update the dirty/accessed state if we set
+ * the dirty bit by hand in the kernel, since the hardware
+ * will do the accessed bit for us, and we don't want to
+ * race with other CPU's that might be updating the dirty
+ * bit at the same time.
  */
 #define update_mmu_cache(vma,address,pte) do { } while (0)
+#define ptep_update_dirty_accessed(__ptep, __entry, __dirty)	\
+	do {							\
+		if (__dirty) set_pte(__ptep, __entry);		\
+	} while (0)
 
 /* Encode and de-code a swap entry */
 #define __swp_type(x)			(((x).val >> 1) & 0x1f)
--- diff/include/asm-i386/processor.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-i386/processor.h	2004-05-27 18:34:18.000000000 +0100
@@ -259,14 +259,8 @@
 
 /*
  * Bus types (default is ISA, but people can check others with these..)
- * pc98 indicates PC98 systems (CBUS)
  */
 extern int MCA_bus;
-#ifdef CONFIG_X86_PC9800
-#define pc98 1
-#else
-#define pc98 0
-#endif
 
 static inline void __monitor(const void *eax, unsigned long ecx,
 		unsigned long edx)
--- diff/include/asm-i386/resource.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -16,8 +16,11 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
+
+#define RLIM_NLIMITS	13
 
-#define RLIM_NLIMITS	11
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +42,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-i386/rwlock.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/rwlock.h	2004-05-27 18:34:18.000000000 +0100
@@ -20,28 +20,52 @@
 #define RW_LOCK_BIAS		 0x01000000
 #define RW_LOCK_BIAS_STR	"0x01000000"
 
-#define __build_read_lock_ptr(rw, helper)   \
-	asm volatile(LOCK "subl $1,(%0)\n\t" \
-		     "js 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tcall " helper "\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     ::"a" (rw) : "memory")
-
-#define __build_read_lock_const(rw, helper)   \
-	asm volatile(LOCK "subl $1,%0\n\t" \
-		     "js 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tpushl %%eax\n\t" \
-		     "leal %0,%%eax\n\t" \
-		     "call " helper "\n\t" \
-		     "popl %%eax\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     :"=m" (*(volatile int *)rw) : : "memory")
+#ifdef CONFIG_SPINLINE
+
+	#define __build_read_lock_ptr(rw, helper)   \
+		asm volatile(LOCK "subl $1,(%0)\n\t" \
+			     "jns 1f\n\t" \
+			     "call " helper "\n\t" \
+			     "1:\t" \
+			     ::"a" (rw) : "memory")
+
+	#define __build_read_lock_const(rw, helper)   \
+		asm volatile(LOCK "subl $1,%0\n\t" \
+			     "jns 1f\n\t" \
+			     "pushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "1:\t" \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#else /* !CONFIG_SPINLINE */
+
+	#define __build_read_lock_ptr(rw, helper)   \
+		asm volatile(LOCK "subl $1,(%0)\n\t" \
+			     "js 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tcall " helper "\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     ::"a" (rw) : "memory")
+
+	#define __build_read_lock_const(rw, helper)   \
+		asm volatile(LOCK "subl $1,%0\n\t" \
+			     "js 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tpushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#endif /* CONFIG_SPINLINE */
+
 
 #define __build_read_lock(rw, helper)	do { \
 						if (__builtin_constant_p(rw)) \
@@ -50,28 +74,51 @@
 							__build_read_lock_ptr(rw, helper); \
 					} while (0)
 
-#define __build_write_lock_ptr(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
-		     "jnz 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tcall " helper "\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     ::"a" (rw) : "memory")
-
-#define __build_write_lock_const(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
-		     "jnz 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tpushl %%eax\n\t" \
-		     "leal %0,%%eax\n\t" \
-		     "call " helper "\n\t" \
-		     "popl %%eax\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     :"=m" (*(volatile int *)rw) : : "memory")
+#ifdef CONFIG_SPINLINE
+
+	#define __build_write_lock_ptr(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+			     "jz 1f\n\t" \
+			     "call " helper "\n\t" \
+			     "1:\n" \
+			     ::"a" (rw) : "memory")
+
+	#define __build_write_lock_const(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+			     "jz 1f\n\t" \
+			     "pushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "1:\n" \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#else /* !CONFIG_SPINLINE */
+
+	#define __build_write_lock_ptr(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+			     "jnz 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tcall " helper "\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     ::"a" (rw) : "memory")
+
+	#define __build_write_lock_const(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+			     "jnz 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tpushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#endif /* CONFIG_SPINLINE */
 
 #define __build_write_lock(rw, helper)	do { \
 						if (__builtin_constant_p(rw)) \
--- diff/include/asm-i386/serial.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/serial.h	2004-05-27 18:34:18.000000000 +0100
@@ -47,19 +47,12 @@
 
 #define C_P(card,port) (((card)<<6|(port)<<3) + 1)
 
-#ifndef CONFIG_X86_PC9800
 #define STD_SERIAL_PORT_DEFNS			\
 	/* UART CLK   PORT IRQ     FLAGS        */			\
 	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
 	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
 	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
 	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
-#else
-#define STD_SERIAL_PORT_DEFNS			\
-	/* UART CLK   PORT IRQ     FLAGS        */			\
-	{ 0, BASE_BAUD, 0x30, 4, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x238, 5, STD_COM_FLAGS },	/* ttyS1 */
-#endif /* CONFIG_X86_PC9800 */
 
 
 #ifdef CONFIG_SERIAL_MANY_PORTS
--- diff/include/asm-i386/spinlock.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-i386/spinlock.h	2004-05-27 18:34:18.000000000 +0100
@@ -42,20 +42,68 @@
 
 #define spin_is_locked(x)	(*(volatile signed char *)(&(x)->lock) <= 0)
 #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
-#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
 
-#define spin_lock_string \
-	"\n1:\t" \
-	"lock ; decb %0\n\t" \
-	"js 2f\n" \
-	LOCK_SECTION_START("") \
-	"2:\t" \
-	"rep;nop\n\t" \
-	"cmpb $0,%0\n\t" \
-	"jle 2b\n\t" \
-	"jmp 1b\n" \
-	LOCK_SECTION_END
+#ifdef CONFIG_SPINLINE
 
+	#define spin_lock_string \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n" \
+		"jmp 3f\n" \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0,%0\n\t" \
+		"jle 2b\n\t" \
+		"jmp 1b\n" \
+		"3:\t"
+
+	#define spin_lock_string_flags \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"jns 3f\n" \
+		"testl $0x200, %1\n\t" \
+		"jz 2f\n\t" \
+		"sti\n\t" \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0, %0\n\t" \
+		"jle 2b\n\t" \
+		"cli\n\t" \
+		"jmp 1b\n" \
+		"3:\t"
+
+#else /* !CONFIG_SPINLINE */
+
+	#define spin_lock_string \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n" \
+		LOCK_SECTION_START("") \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0,%0\n\t" \
+		"jle 2b\n\t" \
+		"jmp 1b\n" \
+		LOCK_SECTION_END
+
+	#define spin_lock_string_flags \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n\t" \
+		LOCK_SECTION_START("") \
+		"2:\t" \
+		"testl $0x200, %1\n\t" \
+		"jz 3f\n\t" \
+		"sti\n\t" \
+		"3:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0, %0\n\t" \
+		"jle 3b\n\t" \
+		"cli\n\t" \
+		"jmp 1b\n" \
+		LOCK_SECTION_END
+
+#endif /* CONFIG_SPINLINE */
 /*
  * This works. Despite all the confusion.
  * (except on PPro SMP or if we are using OOSTORE)
@@ -126,6 +174,20 @@
 		:"=m" (lock->lock) : : "memory");
 }
 
+static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
+{
+#ifdef CONFIG_DEBUG_SPINLOCK
+	__label__ here;
+here:
+	if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
+		printk("eip: %p\n", &&here);
+		BUG();
+	}
+#endif
+	__asm__ __volatile__(
+		spin_lock_string_flags
+		:"=m" (lock->lock) : "r" (flags) : "memory");
+}
 
 /*
  * Read-write spinlocks, allowing multiple readers
@@ -139,6 +201,11 @@
  */
 typedef struct {
 	volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 #ifdef CONFIG_DEBUG_SPINLOCK
 	unsigned magic;
 #endif
@@ -146,11 +213,19 @@
 
 #define RWLOCK_MAGIC	0xdeaf1eed
 
+#ifdef CONFIG_LOCKMETER
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define RWLOCK_MAGIC_INIT	, 0, RWLOCK_MAGIC
+#else
+#define RWLOCK_MAGIC_INIT	, 0
+#endif
+#else /* !CONFIG_LOCKMETER */
 #ifdef CONFIG_DEBUG_SPINLOCK
 #define RWLOCK_MAGIC_INIT	, RWLOCK_MAGIC
 #else
 #define RWLOCK_MAGIC_INIT	/* */
 #endif
+#endif /* !CONFIG_LOCKMETER */
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
 
@@ -197,4 +272,60 @@
 	return 0;
 }
 
+#ifdef CONFIG_LOCKMETER
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+/* FIXME -- replace with assembler */
+	atomic_t *count = (atomic_t *)lock;
+	atomic_dec(count);
+	if (count->counter > 0)
+		return 1;
+	atomic_inc(count);
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK)
+extern void _metered_spin_lock  (spinlock_t *lock);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Matches what is in arch/i386/lib/dec_and_lock.c, except this one is
+ *  "static inline" so that the spin_lock(), if actually invoked, is charged
+ *  against the real caller, not against the catch-all atomic_dec_and_lock
+ */
+static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	int counter;
+	int newcount;
+
+repeat:
+	counter = atomic_read(atomic);
+	newcount = counter-1;
+
+	if (!newcount)
+		goto slow_path;
+
+	asm volatile("lock; cmpxchgl %1,%2"
+		:"=a" (newcount)
+		:"r" (newcount), "m" (atomic->counter), "0" (counter));
+
+	/* If the above failed, "eax" will have changed */
+	if (newcount != counter)
+		goto repeat;
+	return 0;
+
+slow_path:
+	preempt_disable();
+	_metered_spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	_metered_spin_unlock(lock);
+	preempt_enable();
+	return 0;
+}
+
+#define ATOMIC_DEC_AND_LOCK
+#endif
+
 #endif /* __ASM_SPINLOCK_H */
--- diff/include/asm-i386/thread_info.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-i386/thread_info.h	2004-05-27 18:34:18.000000000 +0100
@@ -157,7 +157,7 @@
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
+  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
 
 /*
--- diff/include/asm-i386/timex.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/timex.h	2004-05-27 18:34:18.000000000 +0100
@@ -9,15 +9,11 @@
 #include <linux/config.h>
 #include <asm/msr.h>
 
-#ifdef CONFIG_X86_PC9800
-   extern int CLOCK_TICK_RATE;
-#else
 #ifdef CONFIG_X86_ELAN
 #  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
 #else
 #  define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
 #endif
-#endif
 
 #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
--- diff/include/asm-i386/uaccess.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/uaccess.h	2004-05-27 18:34:18.000000000 +0100
@@ -124,6 +124,7 @@
 };
 
 extern int fixup_exception(struct pt_regs *regs);
+extern int check_exception(struct pt_regs *regs);
 
 /*
  * These are the main single-value transfer routines.  They automatically
--- diff/include/asm-ia64/iosapic.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-ia64/iosapic.h	2004-05-27 18:34:18.000000000 +0100
@@ -60,7 +60,6 @@
 				    unsigned int gsi_base);
 extern int gsi_to_vector (unsigned int gsi);
 extern int gsi_to_irq (unsigned int gsi);
-extern void __init iosapic_parse_prt (void);
 extern void iosapic_enable_intr (unsigned int vector);
 extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
 				  unsigned long trigger);
--- diff/include/asm-ia64/machvec.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-ia64/machvec.h	2004-05-27 18:34:18.000000000 +0100
@@ -19,6 +19,7 @@
 struct scatterlist;
 struct irq_desc;
 struct page;
+struct mm_struct;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t (void);
@@ -26,6 +27,7 @@
 typedef void ia64_mv_send_ipi_t (int, int, int, int);
 typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *);
 typedef void ia64_mv_global_tlb_purge_t (unsigned long, unsigned long, unsigned long);
+typedef void ia64_mv_tlb_migrate_finish_t (struct mm_struct *);
 typedef struct irq_desc *ia64_mv_irq_desc (unsigned int);
 typedef u8 ia64_mv_irq_to_vector (u8);
 typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector);
@@ -72,6 +74,7 @@
 extern void machvec_noop (void);
 extern void machvec_setup (char **);
 extern void machvec_timer_interrupt (int, void *, struct pt_regs *);
+extern void machvec_tlb_migrate_finish (struct mm_struct *);
 extern void machvec_dma_sync_single (struct device *, dma_addr_t, size_t, int);
 extern void machvec_dma_sync_sg (struct device *, struct scatterlist *, int, int);
 
@@ -95,6 +98,7 @@
 #  define platform_send_ipi	ia64_mv.send_ipi
 #  define platform_timer_interrupt	ia64_mv.timer_interrupt
 #  define platform_global_tlb_purge	ia64_mv.global_tlb_purge
+#  define platform_tlb_migrate_finish	ia64_mv.tlb_migrate_finish
 #  define platform_dma_init		ia64_mv.dma_init
 #  define platform_dma_alloc_coherent	ia64_mv.dma_alloc_coherent
 #  define platform_dma_free_coherent	ia64_mv.dma_free_coherent
@@ -140,6 +144,7 @@
 	ia64_mv_send_ipi_t *send_ipi;
 	ia64_mv_timer_interrupt_t *timer_interrupt;
 	ia64_mv_global_tlb_purge_t *global_tlb_purge;
+	ia64_mv_tlb_migrate_finish_t *tlb_migrate_finish;
 	ia64_mv_dma_init *dma_init;
 	ia64_mv_dma_alloc_coherent *dma_alloc_coherent;
 	ia64_mv_dma_free_coherent *dma_free_coherent;
@@ -181,6 +186,7 @@
 	platform_send_ipi,			\
 	platform_timer_interrupt,		\
 	platform_global_tlb_purge,		\
+	platform_tlb_migrate_finish,		\
 	platform_dma_init,			\
 	platform_dma_alloc_coherent,		\
 	platform_dma_free_coherent,		\
@@ -260,6 +266,9 @@
 #ifndef platform_global_tlb_purge
 # define platform_global_tlb_purge	ia64_global_tlb_purge /* default to architected version */
 #endif
+#ifndef platform_tlb_migrate_finish
+# define platform_tlb_migrate_finish machvec_tlb_migrate_finish
+#endif
 #ifndef platform_dma_init
 # define platform_dma_init		swiotlb_init
 #endif
--- diff/include/asm-ia64/machvec_sn2.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-ia64/machvec_sn2.h	2004-05-27 18:34:18.000000000 +0100
@@ -39,6 +39,7 @@
 extern ia64_mv_send_ipi_t sn2_send_IPI;
 extern ia64_mv_timer_interrupt_t sn_timer_interrupt;
 extern ia64_mv_global_tlb_purge_t sn2_global_tlb_purge;
+extern ia64_mv_tlb_migrate_finish_t	sn_tlb_migrate_finish;
 extern ia64_mv_irq_desc sn_irq_desc;
 extern ia64_mv_irq_to_vector sn_irq_to_vector;
 extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq;
@@ -83,6 +84,7 @@
 #define platform_send_ipi		sn2_send_IPI
 #define platform_timer_interrupt	sn_timer_interrupt
 #define platform_global_tlb_purge       sn2_global_tlb_purge
+#define platform_tlb_migrate_finish	sn_tlb_migrate_finish
 #define platform_pci_fixup		sn_pci_fixup
 #define platform_inb			__sn_inb
 #define platform_inw			__sn_inw
--- diff/include/asm-ia64/resource.h	2004-05-19 22:12:42.000000000 +0100
+++ source/include/asm-ia64/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -23,8 +23,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -47,6 +49,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 # endif /* __KERNEL__ */
--- diff/include/asm-ia64/spinlock.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-ia64/spinlock.h	2004-05-27 18:34:18.000000000 +0100
@@ -116,8 +116,18 @@
 typedef struct {
 	volatile int read_counter	: 31;
 	volatile int write_lock		:  1;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 } rwlock_t;
+
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#endif
 
 #define rwlock_init(x)		do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *) (x) != 0)
@@ -133,6 +143,48 @@
 	}										\
 } while (0)
 
+#ifdef CONFIG_LOCKMETER
+/*
+ * HACK: This works, but still have a timing window that affects performance:
+ * we see that no one owns the Write lock, then someone * else grabs for Write
+ * lock before we do a read_lock().
+ * This means that on rare occasions our read_lock() will stall and spin-wait
+ * until we acquire for Read, instead of simply returning a trylock failure.
+ */
+static inline int _raw_read_trylock(rwlock_t *rw)
+{
+	if (rw->write_lock) {
+		return 0;
+	} else {
+		_raw_read_lock(rw);
+		return 1;
+	}
+}
+
+static inline int _raw_write_trylock(rwlock_t *rw)
+{
+	if (!(rw->write_lock)) {
+	    /* isn't currently write-locked... that looks promising... */
+	    if (test_and_set_bit(31, rw) == 0) {
+		/* now it is write-locked by me... */
+		if (rw->read_counter) {
+		    /* really read-locked, so release write-lock and fail */
+		    clear_bit(31, rw);
+		} else {
+		    /* we've the the write-lock, no read-lockers... success! */
+		    barrier();
+		    return 1;
+		}
+
+	    }
+	}
+
+	/* falls through ... fails to write-lock */
+	barrier();
+	return 0;
+}
+#endif
+
 #define _raw_read_unlock(rw)					\
 do {								\
 	rwlock_t *__read_lock_ptr = (rw);			\
@@ -196,4 +248,25 @@
 	clear_bit(31, (x));								\
 })
 
+#ifdef CONFIG_LOCKMETER
+extern void _metered_spin_lock  (spinlock_t *lock);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Use a less efficient, and inline, atomic_dec_and_lock() if lockmetering
+ *  so we can see the callerPC of who is actually doing the spin_lock().
+ *  Otherwise, all we see is the generic rollup of all locks done by
+ *  atomic_dec_and_lock().
+ */
+static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	_metered_spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	_metered_spin_unlock(lock);
+	return 0;
+}
+#define ATOMIC_DEC_AND_LOCK
+#endif
+
 #endif /*  _ASM_IA64_SPINLOCK_H */
--- diff/include/asm-ia64/tlb.h	2004-05-19 22:12:42.000000000 +0100
+++ source/include/asm-ia64/tlb.h	2004-05-27 18:34:18.000000000 +0100
@@ -44,6 +44,7 @@
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
+#include <asm/machvec.h>
 
 #ifdef CONFIG_SMP
 # define FREE_PTE_NR		2048
@@ -211,6 +212,8 @@
 	tlb->end_addr = address + PAGE_SIZE;
 }
 
+#define tlb_migrate_finish(mm)	platform_tlb_migrate_finish(mm)
+
 #define tlb_start_vma(tlb, vma)			do { } while (0)
 #define tlb_end_vma(tlb, vma)			do { } while (0)
 
--- diff/include/asm-m68k/resource.h	2004-05-19 22:12:44.000000000 +0100
+++ source/include/asm-m68k/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +41,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-m68k/setup.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-m68k/setup.h	2004-05-27 18:34:18.000000000 +0100
@@ -357,6 +357,7 @@
 
 #define NUM_MEMINFO	4
 #define CL_SIZE		256
+#define COMMAND_LINE_SIZE	CL_SIZE
 
 #ifndef __ASSEMBLY__
 extern int m68k_num_memory;		/* # of memory blocks found (and used) */
--- diff/include/asm-m68knommu/setup.h	2004-05-19 22:12:45.000000000 +0100
+++ source/include/asm-m68knommu/setup.h	2004-05-27 18:34:18.000000000 +0100
@@ -1 +1,5 @@
 #include <asm-m68k/setup.h>
+
+/* We have a bigger command line buffer. */
+#undef COMMAND_LINE_SIZE
+#define COMMAND_LINE_SIZE	512
--- diff/include/asm-mips/bootinfo.h	2004-05-19 22:12:45.000000000 +0100
+++ source/include/asm-mips/bootinfo.h	2004-05-27 18:34:18.000000000 +0100
@@ -12,6 +12,7 @@
 #define _ASM_BOOTINFO_H
 
 #include <linux/types.h>
+#include <asm/setup.h>
 
 /*
  * The MACH_GROUP_ IDs are the equivalent to PCI vendor IDs; the remaining
@@ -209,7 +210,7 @@
 #define MACH_GROUP_TITAN       22	/* PMC-Sierra Titan		*/
 #define  MACH_TITAN_YOSEMITE	1	/* PMC-Sierra Yosemite		*/
 
-#define CL_SIZE			(256)
+#define CL_SIZE			COMMAND_LINE_SIZE
 
 const char *get_system_type(void);
 
--- diff/include/asm-mips/resource.h	2004-05-19 22:12:46.000000000 +0100
+++ source/include/asm-mips/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -23,8 +23,10 @@
 #define RLIMIT_NPROC 8			/* max number of processes */
 #define RLIMIT_MEMLOCK 9		/* max locked-in-memory address space */
 #define RLIMIT_LOCKS 10			/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS 11			/* Number of limit flavors.  */
+#define RLIM_NLIMITS 13			/* Number of limit flavors.  */
 
 #ifdef __KERNEL__
 
@@ -54,6 +56,8 @@
 	{ 0,             0             },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-mips/spinlock.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-mips/spinlock.h	2004-05-27 18:34:18.000000000 +0100
@@ -92,9 +92,18 @@
 
 typedef struct {
 	volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 } rwlock_t;
 
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
 
 #define rwlock_init(x)  do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
--- diff/include/asm-parisc/cacheflush.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-parisc/cacheflush.h	2004-05-27 18:34:18.000000000 +0100
@@ -79,9 +79,9 @@
 }
 
 #define flush_dcache_mmap_lock(mapping) \
-	spin_lock_irq(&(mapping)->tree_lock)
+	write_lock_irq(&(mapping)->tree_lock)
 #define flush_dcache_mmap_unlock(mapping) \
-	spin_unlock_irq(&(mapping)->tree_lock)
+	write_unlock_irq(&(mapping)->tree_lock)
 
 #define flush_icache_page(vma,page)	do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0)
 
--- diff/include/asm-parisc/resource.h	2004-05-19 22:12:49.000000000 +0100
+++ source/include/asm-parisc/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -40,6 +42,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-parisc/setup.h	2004-05-19 22:12:49.000000000 +0100
+++ source/include/asm-parisc/setup.h	2004-05-27 18:34:18.000000000 +0100
@@ -1,10 +1,6 @@
-/*
- *	Just a place holder. We don't want to have to test x86 before
- *	we include stuff
- */
+#ifndef _PARISC_SETUP_H
+#define _PARISC_SETUP_H
 
-#ifndef _i386_SETUP_H
-#define _i386_SETUP_H
+#define COMMAND_LINE_SIZE	1024
 
-
-#endif /* _i386_SETUP_H */
+#endif /* _PARISC_SETUP_H */
--- diff/include/asm-ppc/machdep.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/machdep.h	2004-05-27 18:34:18.000000000 +0100
@@ -106,7 +106,6 @@
 };
 
 extern struct machdep_calls ppc_md;
-#define COMMAND_LINE_SIZE 512
 extern char cmd_line[COMMAND_LINE_SIZE];
 
 extern void setup_pci_ptrs(void);
--- diff/include/asm-ppc/resource.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/resource.h	2004-05-27 18:34:18.000000000 +0100
@@ -12,8 +12,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit(?) */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -37,6 +39,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc/setup.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/setup.h	2004-05-27 18:34:18.000000000 +0100
@@ -6,6 +6,9 @@
 #define m68k_memory memory
 
 #include <asm-m68k/setup.h>
+/* We have a bigger command line buffer. */
+#undef COMMAND_LINE_SIZE
+#define COMMAND_LINE_SIZE	512
 
 #endif /* _PPC_SETUP_H */
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc64/bitops.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/bitops.h	2004-05-27 18:34:18.000000000 +0100
@@ -154,6 +154,20 @@
 	return (old & mask) != 0;
 }
 
+static __inline__ void set_bits(unsigned long mask, unsigned long *addr)
+{
+	unsigned long old;
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%3		# set_bit\n\
+	or	%0,%0,%2\n\
+	stdcx.	%0,0,%3\n\
+	bne-	1b"
+	: "=&r" (old), "=m" (*addr)
+	: "r" (mask), "r" (addr), "m" (*addr)
+	: "cc");
+}
+
 /*
  * non-atomic versions
  */
--- diff/include/asm-ppc64/eeh.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/eeh.h	2004-05-27 18:34:18.000000000 +0100
@@ -215,7 +215,7 @@
 
 static inline void eeh_outb(u8 val, unsigned long port) {
 	if (_IO_IS_VALID(port))
-		return out_8((u8 *)(port+pci_io_base), val);
+		out_8((u8 *)(port+pci_io_base), val);
 }
 
 static inline u16 eeh_inw(unsigned long port) {
@@ -230,7 +230,7 @@
 
 static inline void eeh_outw(u16 val, unsigned long port) {
 	if (_IO_IS_VALID(port))
-		return out_le16((u16 *)(port+pci_io_base), val);
+		out_le16((u16 *)(port+pci_io_base), val);
 }
 
 static inline u32 eeh_inl(unsigned long port) {
@@ -245,7 +245,7 @@
 
 static inline void eeh_outl(u32 val, unsigned long port) {
 	if (_IO_IS_VALID(port))
-		return out_le32((u32 *)(port+pci_io_base), val);
+		out_le32((u32 *)(port+pci_io_base), val);
 }
 
 /* in-string eeh macros */
--- diff/include/asm-ppc64/iommu.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/iommu.h	2004-05-27 18:34:18.000000000 +0100
@@ -29,10 +29,10 @@
 
 /*
  * IOMAP_MAX_ORDER defines the largest contiguous block
- * of dma (tce) space we can get.  IOMAP_MAX_ORDER = 10 
- * allows up to 2**9 pages (512 * 4096) = 2 MB
+ * of dma (tce) space we can get.  IOMAP_MAX_ORDER = 13
+ * allows up to 2**12 pages (4096 * 4096) = 16 MB
  */
-#define IOMAP_MAX_ORDER 10
+#define IOMAP_MAX_ORDER 13
 
 /*
  * Tces come in two formats, one for the virtual bus and a different
--- diff/include/asm-ppc64/irq.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/irq.h	2004-05-27 18:34:18.000000000 +0100
@@ -9,6 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/threads.h>
 #include <asm/atomic.h>
 
 /*
@@ -77,7 +78,26 @@
 
 struct irqaction;
 struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+int handle_irq_event(int, struct pt_regs *, struct irqaction *);
+
+#ifdef CONFIG_IRQSTACKS
+/*
+ * Per-cpu stacks for handling hard and soft interrupts.
+ */
+extern struct thread_info *hardirq_ctx[NR_CPUS];
+extern struct thread_info *softirq_ctx[NR_CPUS];
+
+extern void irq_ctx_init(void);
+extern void call_do_softirq(struct thread_info *tp);
+extern int call_handle_irq_event(int irq, struct pt_regs *regs,
+			struct irqaction *action, struct thread_info *tp);
+
+#define __ARCH_HAS_DO_SOFTIRQ
+
+#else
+#define irq_ctx_init()
+
+#endif /* CONFIG_IRQSTACKS */
 
 #endif /* _ASM_IRQ_H */
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc64/machdep.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/machdep.h	2004-05-27 18:34:19.000000000 +0100
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/seq_file.h>
+#include <linux/init.h>
 #include <linux/dma-mapping.h>
 
 struct pt_regs;
@@ -112,9 +113,7 @@
 };
 
 extern struct machdep_calls ppc_md;
-#define COMMAND_LINE_SIZE 512
 extern char cmd_line[COMMAND_LINE_SIZE];
-extern char saved_command_line[COMMAND_LINE_SIZE];
 
 /* Functions to produce codes on the leds.
  * The SRC code should be unique for the message category and should
--- diff/include/asm-ppc64/mmu.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/mmu.h	2004-05-27 18:34:19.000000000 +0100
@@ -204,7 +204,7 @@
 		page = vpn & 0xffff;
 	}
 
-	return (vsid & 0x7fffffffff) ^ page;
+	return (vsid & 0x7fffffffffUL) ^ page;
 }
 
 static inline void __tlbie(unsigned long va, int large)
--- diff/include/asm-ppc64/mmu_context.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/mmu_context.h	2004-05-27 18:34:19.000000000 +0100
@@ -175,8 +175,8 @@
 #define activate_mm(active_mm, mm) \
 	switch_mm(active_mm, mm, current);
 
-#define VSID_RANDOMIZER 42470972311
-#define VSID_MASK	0xfffffffff
+#define VSID_RANDOMIZER 42470972311UL
+#define VSID_MASK	0xfffffffffUL
 
 
 /* This is only valid for kernel (including vmalloc, imalloc and bolted) EA's
--- diff/include/asm-ppc64/mmzone.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/mmzone.h	2004-05-27 18:34:19.000000000 +0100
@@ -23,7 +23,6 @@
 extern cpumask_t numa_cpumask_lookup_table[];
 extern int nr_cpus_in_node[];
 
-#define MAX_MEMORY (1UL << 41)
 /* 16MB regions */
 #define MEMORY_INCREMENT_SHIFT 24
 #define MEMORY_INCREMENT (1UL << MEMORY_INCREMENT_SHIFT)
--- diff/include/asm-ppc64/page.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/page.h	2004-05-27 18:34:19.000000000 +0100
@@ -12,18 +12,20 @@
 
 #include <linux/config.h>
 
-/* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT	12
-#ifndef __ASSEMBLY__
-# define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#ifdef __ASSEMBLY__
+  #define ASM_CONST(x) x
 #else
-# define PAGE_SIZE	(1 << PAGE_SHIFT)
+  #define ASM_CONST(x) x##UL
 #endif
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT	12
+#define PAGE_SIZE	(ASM_CONST(1) << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 #define PAGE_OFFSET_MASK (PAGE_SIZE-1)
 
 #define SID_SHIFT       28
-#define SID_MASK        0xfffffffff
+#define SID_MASK        0xfffffffffUL
 #define GET_ESID(x)     (((x) >> SID_SHIFT) & SID_MASK)
 
 #ifdef CONFIG_HUGETLB_PAGE
@@ -196,11 +198,11 @@
 /*       KERNELBASE is defined for performance reasons. */
 /*       When KERNELBASE moves, those macros may have   */
 /*             to change!                               */
-#define PAGE_OFFSET     0xC000000000000000
+#define PAGE_OFFSET     ASM_CONST(0xC000000000000000)
 #define KERNELBASE      PAGE_OFFSET
-#define VMALLOCBASE     0xD000000000000000
-#define IOREGIONBASE    0xE000000000000000
-#define EEHREGIONBASE   0xA000000000000000
+#define VMALLOCBASE     0xD000000000000000UL
+#define IOREGIONBASE    0xE000000000000000UL
+#define EEHREGIONBASE   0xA000000000000000UL
 
 #define IO_REGION_ID       (IOREGIONBASE>>REGION_SHIFT)
 #define EEH_REGION_ID      (EEHREGIONBASE>>REGION_SHIFT)
--- diff/include/asm-ppc64/pgalloc.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-ppc64/pgalloc.h	2004-05-27 18:34:19.000000000 +0100
@@ -101,33 +101,7 @@
 
 DECLARE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
 
-static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)
-{
-	/* This is safe as we are holding page_table_lock */
-        cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
-	struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-
-	if (atomic_read(&tlb->mm->mm_users) < 2 ||
-	    cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
-		pte_free(ptepage);
-		return;
-	}
-
-	if (*batchp == NULL) {
-		*batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
-		if (*batchp == NULL) {
-			pte_free_now(ptepage);
-			return;
-		}
-		(*batchp)->index = 0;
-	}
-	(*batchp)->pages[(*batchp)->index++] = ptepage;
-	if ((*batchp)->index == PTE_FREELIST_SIZE) {
-		pte_free_submit(*batchp);
-		*batchp = NULL;
-	}
-}
-
+void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage);
 #define __pmd_free_tlb(tlb, pmd)	__pte_free_tlb(tlb, virt_to_page(pmd))
 
 #define check_pgt_cache()	do { } while (0)
--- diff/include/asm-ppc64/resource.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/resource.h	2004-05-27 18:34:19.000000000 +0100
@@ -21,8 +21,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit(?) */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -46,6 +48,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc64/setup.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/setup.h	2004-05-27 18:34:19.000000000 +0100
@@ -1,6 +1,6 @@
 #ifndef _PPC_SETUP_H
 #define _PPC_SETUP_H
 
-/* This is a place holder include */
+#define COMMAND_LINE_SIZE 512
 
 #endif /* _PPC_SETUP_H */
--- diff/include/asm-ppc64/spinlock.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-ppc64/spinlock.h	2004-05-27 18:34:19.000000000 +0100
@@ -103,7 +103,7 @@
 	unsigned long tmp2;
 
 	__asm__ __volatile__(
-	"b		2f		# spin_lock\n\
+	"b		3f		# spin_lock\n\
 1:	mfmsr		%1\n\
 	mtmsrd		%3,1\n\
 2:"	HMT_LOW
--- diff/include/asm-ppc64/thread_info.h	2004-05-19 22:12:52.000000000 +0100
+++ source/include/asm-ppc64/thread_info.h	2004-05-27 18:34:19.000000000 +0100
@@ -69,10 +69,6 @@
 #define get_thread_info(ti)	get_task_struct((ti)->task)
 #define put_thread_info(ti)	put_task_struct((ti)->task)
 
-#if THREAD_SIZE != (4*PAGE_SIZE)
-#error update vmlinux.lds and current_thread_info to match
-#endif
-
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
--- diff/include/asm-s390/pgtable.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-s390/pgtable.h	2004-05-27 18:34:19.000000000 +0100
@@ -580,7 +580,8 @@
 
 static inline void
 ptep_establish(struct vm_area_struct *vma, 
-	       unsigned long address, pte_t *ptep, pte_t entry)
+	       unsigned long address, pte_t *ptep,
+	       pte_t entry, int dirty)
 {
 	ptep_clear_flush(vma, address, ptep);
 	set_pte(ptep, entry);
--- diff/include/asm-s390/resource.h	2004-05-19 22:12:52.000000000 +0100
+++ source/include/asm-s390/resource.h	2004-05-27 18:34:19.000000000 +0100
@@ -24,8 +24,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
-  
-#define RLIM_NLIMITS	11
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
+
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -48,6 +50,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-sh/resource.h	2004-05-19 22:12:53.000000000 +0100
+++ source/include/asm-sh/resource.h	2004-05-27 18:34:19.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -40,6 +42,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-sparc/resource.h	2004-05-19 22:12:55.000000000 +0100
+++ source/include/asm-sparc/resource.h	2004-05-27 18:34:19.000000000 +0100
@@ -19,11 +19,13 @@
 #define RLIMIT_RSS	5		/* max resident set size */
 #define RLIMIT_NOFILE	6		/* max number of open files */
 #define RLIMIT_NPROC	7		/* max number of processes */
-#define RLIMIT_MEMLOCK  8               /* max locked-in-memory address space */
-#define RLIMIT_AS       9               /* address space limit */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
+#define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -44,7 +46,9 @@
     {INR_OPEN, INR_OPEN}, {0, 0},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
-    {RLIM_INFINITY, RLIM_INFINITY}	\
+    {RLIM_INFINITY, RLIM_INFINITY},	\
+    {MAX_SIGPENDING, MAX_SIGPENDING},	\
+    {MQ_BYTES_MAX, MQ_BYTES_MAX},	\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-sparc/setup.h	2004-05-19 22:12:55.000000000 +0100
+++ source/include/asm-sparc/setup.h	2004-05-27 18:34:19.000000000 +0100
@@ -5,5 +5,6 @@
 #ifndef _SPARC_SETUP_H
 #define _SPARC_SETUP_H
 
+#define COMMAND_LINE_SIZE	256
 
 #endif /* _SPARC_SETUP_H */
--- diff/include/asm-sparc64/resource.h	2004-05-19 22:12:56.000000000 +0100
+++ source/include/asm-sparc64/resource.h	2004-05-27 18:34:19.000000000 +0100
@@ -19,11 +19,13 @@
 #define RLIMIT_RSS	5		/* max resident set size */
 #define RLIMIT_NOFILE	6		/* max number of open files */
 #define RLIMIT_NPROC	7		/* max number of processes */
-#define RLIMIT_MEMLOCK  8               /* max locked-in-memory address space */
-#define RLIMIT_AS       9               /* address space limit */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
+#define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -43,7 +45,9 @@
     {INR_OPEN, INR_OPEN}, {0, 0},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
-    {RLIM_INFINITY, RLIM_INFINITY}	\
+    {RLIM_INFINITY, RLIM_INFINITY},	\
+    {MAX_SIGPENDING, MAX_SIGPENDING},	\
+    {MQ_BYTES_MAX, MQ_BYTES_MAX},	\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-sparc64/setup.h	2004-05-19 22:12:56.000000000 +0100
+++ source/include/asm-sparc64/setup.h	2004-05-27 18:34:19.000000000 +0100
@@ -5,5 +5,6 @@
 #ifndef _SPARC64_SETUP_H
 #define _SPARC64_SETUP_H
 
+#define COMMAND_LINE_SIZE	256
 
 #endif /* _SPARC64_SETUP_H */
--- diff/include/asm-sparc64/spinlock.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-sparc64/spinlock.h	2004-05-27 18:34:19.000000000 +0100
@@ -31,15 +31,23 @@
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned char spinlock_t;
-#define SPIN_LOCK_UNLOCKED	0
+typedef struct {
+	unsigned char lock;
+	unsigned int  index;
+} spinlock_t;
 
-#define spin_lock_init(lock)	(*((unsigned char *)(lock)) = 0)
-#define spin_is_locked(lock)	(*((volatile unsigned char *)(lock)) != 0)
+#ifdef CONFIG_LOCKMETER
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) {0, 0}
+#else
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
+#endif
 
-#define spin_unlock_wait(lock)	\
+#define spin_lock_init(__lock)	do { *(__lock) = SPIN_LOCK_UNLOCKED; } while(0)
+#define spin_is_locked(__lock)	(*((volatile unsigned char *)(&((__lock)->lock))) != 0)
+
+#define spin_unlock_wait(__lock)	\
 do {	membar("#LoadLoad");	\
-} while(*((volatile unsigned char *)lock))
+} while(*((volatile unsigned char *)(&(((spinlock_t *)__lock)->lock))))
 
 static __inline__ void _raw_spin_lock(spinlock_t *lock)
 {
@@ -112,17 +120,31 @@
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned int rwlock_t;
-#define RW_LOCK_UNLOCKED	0
-#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
-#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED)
+#ifdef CONFIG_LOCKMETER
+typedef struct {
+	unsigned int lock;
+	unsigned int index;
+	unsigned int cpu;
+} rwlock_t;
+#define RW_LOCK_UNLOCKED       (rwlock_t) { 0, 0, 0xff }
+#else
+typedef struct {
+	unsigned int lock;
+} rwlock_t;
+#define RW_LOCK_UNLOCKED        (rwlock_t) { 0 }
+#endif
+
+#define rwlock_init(lp)		do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_is_locked(x)	((x)->lock != 0)
 
+extern int __read_trylock(rwlock_t *);
 extern void __read_lock(rwlock_t *);
 extern void __read_unlock(rwlock_t *);
 extern void __write_lock(rwlock_t *);
 extern void __write_unlock(rwlock_t *);
 extern int __write_trylock(rwlock_t *);
 
+#define _raw_read_trylock(p)	__read_trylock(p)
 #define _raw_read_lock(p)	__read_lock(p)
 #define _raw_read_unlock(p)	__read_unlock(p)
 #define _raw_write_lock(p)	__write_lock(p)
--- diff/include/asm-v850/resource.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-v850/resource.h	2004-05-27 18:34:19.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +41,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-x86_64/bootsetup.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-x86_64/bootsetup.h	2004-05-27 18:34:19.000000000 +0100
@@ -30,7 +30,6 @@
 #define EDD_NR     (*(unsigned char *) (PARAM+EDDNR))
 #define EDD_BUF     ((struct edd_info *) (PARAM+EDDBUF))
 #define COMMAND_LINE saved_command_line
-#define COMMAND_LINE_SIZE 256
 
 #define RAMDISK_IMAGE_START_MASK  	0x07FF
 #define RAMDISK_PROMPT_FLAG		0x8000
--- diff/include/asm-x86_64/mpspec.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/asm-x86_64/mpspec.h	2004-05-27 18:34:19.000000000 +0100
@@ -189,7 +189,7 @@
 extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
 extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
 extern void mp_config_acpi_legacy_irqs (void);
-extern void mp_parse_prt (void);
+extern void mp_register_gsi (u32 gsi, int edge_level, int active_high_low);
 #endif /*CONFIG_X86_IO_APIC*/
 #endif
 
--- diff/include/asm-x86_64/processor.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-x86_64/processor.h	2004-05-27 18:34:19.000000000 +0100
@@ -345,17 +345,7 @@
 /* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
 #define MICROCODE_IOCFREE	_IO('6',0)
 
-/* generic versions from gas */
-#define GENERIC_NOP1	".byte 0x90\n"
-#define GENERIC_NOP2    	".byte 0x89,0xf6\n"
-#define GENERIC_NOP3        ".byte 0x8d,0x76,0x00\n"
-#define GENERIC_NOP4        ".byte 0x8d,0x74,0x26,0x00\n"
-#define GENERIC_NOP5        GENERIC_NOP1 GENERIC_NOP4
-#define GENERIC_NOP6	".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n"
-#define GENERIC_NOP7	".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n"
-#define GENERIC_NOP8	GENERIC_NOP1 GENERIC_NOP7
 
-#ifdef CONFIG_MK8
 #define ASM_NOP1 K8_NOP1
 #define ASM_NOP2 K8_NOP2
 #define ASM_NOP3 K8_NOP3
@@ -364,16 +354,6 @@
 #define ASM_NOP6 K8_NOP6
 #define ASM_NOP7 K8_NOP7
 #define ASM_NOP8 K8_NOP8
-#else
-#define ASM_NOP1 GENERIC_NOP1
-#define ASM_NOP2 GENERIC_NOP2
-#define ASM_NOP3 GENERIC_NOP3
-#define ASM_NOP4 GENERIC_NOP4
-#define ASM_NOP5 GENERIC_NOP5
-#define ASM_NOP6 GENERIC_NOP6
-#define ASM_NOP7 GENERIC_NOP7
-#define ASM_NOP8 GENERIC_NOP8
-#endif
 
 /* Opteron nops */
 #define K8_NOP1 ".byte 0x90\n"
--- diff/include/asm-x86_64/resource.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/asm-x86_64/resource.h	2004-05-27 18:34:19.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +41,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-x86_64/setup.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/asm-x86_64/setup.h	2004-05-27 18:34:19.000000000 +0100
@@ -1,10 +1,6 @@
-/*
- *	Just a place holder. We don't want to have to test x86 before
- *	we include stuff
- */
-
 #ifndef _x8664_SETUP_H
 #define _x8664_SETUP_H
 
+#define COMMAND_LINE_SIZE	256
 
 #endif
--- diff/include/asm-x86_64/unistd.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/asm-x86_64/unistd.h	2004-05-27 18:34:19.000000000 +0100
@@ -535,11 +535,11 @@
 #define __NR_vserver		236
 __SYSCALL(__NR_vserver, sys_ni_syscall)
 #define __NR_mbind 		237
-__SYSCALL(__NR_mbind, sys_ni_syscall)
+__SYSCALL(__NR_mbind, sys_mbind)
 #define __NR_set_mempolicy 	238
-__SYSCALL(__NR_set_mempolicy, sys_ni_syscall)
+__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
 #define __NR_get_mempolicy 	239
-__SYSCALL(__NR_get_mempolicy, sys_ni_syscall)
+__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
 #define __NR_mq_open 		240
 __SYSCALL(__NR_mq_open, sys_mq_open)
 #define __NR_mq_unlink 		241
--- diff/include/linux/acpi.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/acpi.h	2004-05-27 18:34:19.000000000 +0100
@@ -437,7 +437,7 @@
 struct pci_dev;
 
 int acpi_pci_irq_enable (struct pci_dev *dev);
-int acpi_pci_irq_init (void);
+unsigned int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low);
 int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
 struct acpi_pci_driver {
--- diff/include/linux/binfmts.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/binfmts.h	2004-05-27 18:34:19.000000000 +0100
@@ -35,9 +35,13 @@
 	char * interp;		/* Name of the binary really executed. Most
 				   of the time same as filename, but could be
 				   different for binfmt_{misc,script} */
+	unsigned long interp_flags;
 	unsigned long loader, exec;
 };
 
+#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
+#define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
+
 /*
  * This structure defines the functions that are used to load the binary formats that
  * linux accepts.
--- diff/include/linux/bio.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/bio.h	2004-05-27 18:34:19.000000000 +0100
@@ -102,6 +102,7 @@
 #define BIO_SEG_VALID	3	/* nr_hw_seg valid */
 #define BIO_CLONED	4	/* doesn't own data */
 #define BIO_BOUNCED	5	/* bio is a bounce bio */
+#define BIO_EOPNOTSUPP	6	/* not supported */
 #define bio_flagged(bio, flag)	((bio)->bi_flags & (1 << (flag)))
 
 /*
@@ -141,6 +142,8 @@
 #define bio_data(bio)		(page_address(bio_page((bio))) + bio_offset((bio)))
 #define bio_barrier(bio)	((bio)->bi_rw & (1 << BIO_RW_BARRIER))
 #define bio_sync(bio)		((bio)->bi_rw & (1 << BIO_RW_SYNC))
+#define bio_failfast(bio)	((bio)->bi_rw & (1 << BIO_RW_FAILFAST))
+#define bio_rw_ahead(bio)	((bio)->bi_rw & (1 << BIO_RW_AHEAD))
 
 /*
  * will die
--- diff/include/linux/blkdev.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/blkdev.h	2004-05-27 18:34:19.000000000 +0100
@@ -195,6 +195,8 @@
 	__REQ_PM_SUSPEND,	/* suspend request */
 	__REQ_PM_RESUME,	/* resume request */
 	__REQ_PM_SHUTDOWN,	/* shutdown request */
+	__REQ_BAR_PREFLUSH,	/* barrier pre-flush done */
+	__REQ_BAR_POSTFLUSH,	/* barrier post-flush */
 	__REQ_NR_BITS,		/* stops here */
 };
 
@@ -220,6 +222,8 @@
 #define REQ_PM_SUSPEND	(1 << __REQ_PM_SUSPEND)
 #define REQ_PM_RESUME	(1 << __REQ_PM_RESUME)
 #define REQ_PM_SHUTDOWN	(1 << __REQ_PM_SHUTDOWN)
+#define REQ_BAR_PREFLUSH	(1 << __REQ_BAR_PREFLUSH)
+#define REQ_BAR_POSTFLUSH	(1 << __REQ_BAR_POSTFLUSH)
 
 /*
  * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME
@@ -248,6 +252,7 @@
 struct bio_vec;
 typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
 typedef void (activity_fn) (void *data, int rw);
+typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *);
 
 enum blk_queue_state {
 	Queue_down,
@@ -290,6 +295,7 @@
 	unplug_fn		*unplug_fn;
 	merge_bvec_fn		*merge_bvec_fn;
 	activity_fn		*activity_fn;
+	issue_flush_fn		*issue_flush_fn;
 
 	/*
 	 * Auto-unplugging state
@@ -373,6 +379,7 @@
 #define QUEUE_FLAG_DEAD		5	/* queue being torn down */
 #define QUEUE_FLAG_REENTER	6	/* Re-entrancy avoidance */
 #define QUEUE_FLAG_PLUGGED	7	/* queue is plugged */
+#define QUEUE_FLAG_ORDERED	8	/* supports ordered writes */
 
 #define blk_queue_plugged(q)	test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
 #define blk_queue_tagged(q)	test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
@@ -390,6 +397,10 @@
 #define blk_pm_request(rq)	\
 	((rq)->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME))
 
+#define blk_barrier_rq(rq)	((rq)->flags & REQ_HARDBARRIER)
+#define blk_barrier_preflush(rq)	((rq)->flags & REQ_BAR_PREFLUSH)
+#define blk_barrier_postflush(rq)	((rq)->flags & REQ_BAR_POSTFLUSH)
+
 #define list_entry_rq(ptr)	list_entry((ptr), struct request, queuelist)
 
 #define rq_data_dir(rq)		((rq)->flags & 1)
@@ -560,6 +571,14 @@
 extern int process_that_request_first(struct request *, unsigned int);
 extern void end_request(struct request *req, int uptodate);
 
+/*
+ * end_that_request_first/chunk() takes an uptodate argument. we account
+ * any value <= as an io error. 0 means -EIO for compatability reasons,
+ * any other < 0 value is the direct error type. An uptodate value of
+ * 1 indicates successful io completion
+ */
+#define end_io_error(uptodate)	(unlikely((uptodate) <= 0))
+
 static inline void blkdev_dequeue_request(struct request *req)
 {
 	BUG_ON(list_empty(&req->queuelist));
@@ -588,6 +607,9 @@
 extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(request_queue_t *, int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
+extern void blk_queue_ordered(request_queue_t *, int);
+extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *);
+extern int blkdev_scsi_issue_flush_fn(request_queue_t *, struct gendisk *, sector_t *);
 
 extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
@@ -615,6 +637,7 @@
 
 extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
 extern void blk_rq_prep_restart(struct request *);
+extern int blkdev_issue_flush(struct block_device *, sector_t *);
 
 #define MAX_PHYS_SEGMENTS 128
 #define MAX_HW_SEGMENTS 128
--- diff/include/linux/buffer_head.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/buffer_head.h	2004-05-27 18:34:19.000000000 +0100
@@ -26,6 +26,7 @@
 	BH_Delay,	/* Buffer is not yet allocated on disk */
 	BH_Boundary,	/* Block is followed by a discontiguity */
 	BH_Write_EIO,	/* I/O error on write */
+	BH_Ordered,	/* ordered write */
 
 	BH_PrivateStart,/* not a state bit, but the first bit available
 			 * for private allocation by other entities
@@ -110,7 +111,8 @@
 BUFFER_FNS(Async_Write, async_write)
 BUFFER_FNS(Delay, delay)
 BUFFER_FNS(Boundary, boundary)
-BUFFER_FNS(Write_EIO,write_io_error)
+BUFFER_FNS(Write_EIO, write_io_error)
+BUFFER_FNS(Ordered, ordered)
 
 #define bh_offset(bh)		((unsigned long)(bh)->b_data & ~PAGE_MASK)
 #define touch_buffer(bh)	mark_page_accessed(bh->b_page)
@@ -172,8 +174,8 @@
 void FASTCALL(unlock_buffer(struct buffer_head *bh));
 void FASTCALL(__lock_buffer(struct buffer_head *bh));
 void ll_rw_block(int, int, struct buffer_head * bh[]);
-void sync_dirty_buffer(struct buffer_head *bh);
-void submit_bh(int, struct buffer_head *);
+int sync_dirty_buffer(struct buffer_head *bh);
+int submit_bh(int, struct buffer_head *);
 void write_boundary_block(struct block_device *bdev,
 			sector_t bblock, unsigned blocksize);
 
--- diff/include/linux/compat_ioctl.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/compat_ioctl.h	2004-05-27 18:34:19.000000000 +0100
@@ -138,6 +138,7 @@
 COMPATIBLE_IOCTL(DM_TABLE_STATUS_32)
 COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32)
 COMPATIBLE_IOCTL(DM_VERSION)
+COMPATIBLE_IOCTL(DM_REMOVE_ALL)
 COMPATIBLE_IOCTL(DM_LIST_DEVICES)
 COMPATIBLE_IOCTL(DM_DEV_CREATE)
 COMPATIBLE_IOCTL(DM_DEV_REMOVE)
--- diff/include/linux/compiler-gcc.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/compiler-gcc.h	2004-05-27 18:34:19.000000000 +0100
@@ -13,5 +13,5 @@
    shouldn't recognize the original var, and make assumptions about it */
 #define RELOC_HIDE(ptr, off)					\
   ({ unsigned long __ptr;					\
-    __asm__ ("" : "=g"(__ptr) : "0"(ptr));		\
+	__asm__ ("" : "=r"(__ptr) : "0"(ptr));			\
     (typeof(ptr)) (__ptr + (off)); })
--- diff/include/linux/config.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/config.h	2004-05-27 18:34:19.000000000 +0100
@@ -2,5 +2,8 @@
 #define _LINUX_CONFIG_H
 
 #include <linux/autoconf.h>
+#ifdef CONFIG_X86
+#include <asm/kgdb.h>
+#endif
 
 #endif
--- diff/include/linux/ext3_fs.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/ext3_fs.h	2004-05-27 18:34:19.000000000 +0100
@@ -33,11 +33,10 @@
 #undef EXT3FS_DEBUG
 
 /*
- * Define EXT3_PREALLOCATE to preallocate data blocks for expanding files
+ * Define EXT3_RESERVATION to reserve data blocks for expanding files
  */
-#undef  EXT3_PREALLOCATE /* @@@ Fix this! */
-#define EXT3_DEFAULT_PREALLOC_BLOCKS	8
-
+#define EXT3_DEFAULT_RESERVE_BLOCKS     8
+#define EXT3_MAX_RESERVE_BLOCKS         1024
 /*
  * Always enable hashed directories
  */
@@ -208,6 +207,8 @@
 #ifdef CONFIG_JBD_DEBUG
 #define EXT3_IOC_WAIT_FOR_READONLY	_IOR('f', 99, long)
 #endif
+#define EXT3_IOC_GETRSVSZ		_IOR('r', 1, long)
+#define EXT3_IOC_SETRSVSZ		_IOW('r', 2, long)
 
 /*
  * Structure of an inode on the disk
@@ -306,24 +307,26 @@
 /*
  * Mount flags
  */
-#define EXT3_MOUNT_CHECK		0x0001	/* Do mount-time checks */
-#define EXT3_MOUNT_OLDALLOC		0x0002  /* Don't use the new Orlov allocator */
-#define EXT3_MOUNT_GRPID		0x0004	/* Create files with directory's group */
-#define EXT3_MOUNT_DEBUG		0x0008	/* Some debugging messages */
-#define EXT3_MOUNT_ERRORS_CONT		0x0010	/* Continue on errors */
-#define EXT3_MOUNT_ERRORS_RO		0x0020	/* Remount fs ro on errors */
-#define EXT3_MOUNT_ERRORS_PANIC		0x0040	/* Panic on errors */
-#define EXT3_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */
-#define EXT3_MOUNT_NOLOAD		0x0100	/* Don't use existing journal*/
-#define EXT3_MOUNT_ABORT		0x0200	/* Fatal error detected */
-#define EXT3_MOUNT_DATA_FLAGS		0x0C00	/* Mode for data writes: */
-  #define EXT3_MOUNT_JOURNAL_DATA	0x0400	/* Write data to journal */
-  #define EXT3_MOUNT_ORDERED_DATA	0x0800	/* Flush data before commit */
-  #define EXT3_MOUNT_WRITEBACK_DATA	0x0C00	/* No data ordering */
-#define EXT3_MOUNT_UPDATE_JOURNAL	0x1000	/* Update the journal format */
-#define EXT3_MOUNT_NO_UID32		0x2000  /* Disable 32-bit UIDs */
-#define EXT3_MOUNT_XATTR_USER		0x4000	/* Extended user attributes */
-#define EXT3_MOUNT_POSIX_ACL		0x8000	/* POSIX Access Control Lists */
+#define EXT3_MOUNT_CHECK		0x00001	/* Do mount-time checks */
+#define EXT3_MOUNT_OLDALLOC		0x00002  /* Don't use the new Orlov allocator */
+#define EXT3_MOUNT_GRPID		0x00004	/* Create files with directory's group */
+#define EXT3_MOUNT_DEBUG		0x00008	/* Some debugging messages */
+#define EXT3_MOUNT_ERRORS_CONT		0x00010	/* Continue on errors */
+#define EXT3_MOUNT_ERRORS_RO		0x00020	/* Remount fs ro on errors */
+#define EXT3_MOUNT_ERRORS_PANIC		0x00040	/* Panic on errors */
+#define EXT3_MOUNT_MINIX_DF		0x00080	/* Mimics the Minix statfs */
+#define EXT3_MOUNT_NOLOAD		0x00100	/* Don't use existing journal*/
+#define EXT3_MOUNT_ABORT		0x00200	/* Fatal error detected */
+#define EXT3_MOUNT_DATA_FLAGS		0x00C00	/* Mode for data writes: */
+#define EXT3_MOUNT_JOURNAL_DATA		0x00400	/* Write data to journal */
+#define EXT3_MOUNT_ORDERED_DATA		0x00800	/* Flush data before commit */
+#define EXT3_MOUNT_WRITEBACK_DATA	0x00C00	/* No data ordering */
+#define EXT3_MOUNT_UPDATE_JOURNAL	0x01000	/* Update the journal format */
+#define EXT3_MOUNT_NO_UID32		0x02000  /* Disable 32-bit UIDs */
+#define EXT3_MOUNT_XATTR_USER		0x04000	/* Extended user attributes */
+#define EXT3_MOUNT_POSIX_ACL		0x08000	/* POSIX Access Control Lists */
+#define EXT3_MOUNT_RESERVATION		0x10000	/* Preallocation */
+#define EXT3_MOUNT_BARRIER		0x20000 /* Use block barriers */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
@@ -680,8 +683,7 @@
 /* balloc.c */
 extern int ext3_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
-extern int ext3_new_block (handle_t *, struct inode *, unsigned long,
-					    __u32 *, __u32 *, int *);
+extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
 extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
 			      unsigned long);
 extern unsigned long ext3_count_free_blocks (struct super_block *);
@@ -689,6 +691,7 @@
 extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
 						    unsigned int block_group,
 						    struct buffer_head ** bh);
+extern int ext3_should_retry_alloc(struct super_block *sb, int *retries);
 
 /* dir.c */
 extern int ext3_check_dir_entry(const char *, struct inode *,
@@ -728,6 +731,7 @@
 extern void ext3_delete_inode (struct inode *);
 extern int  ext3_sync_inode (handle_t *, struct inode *);
 extern void ext3_discard_prealloc (struct inode *);
+extern void ext3_discard_reservation (struct inode *);
 extern void ext3_dirty_inode(struct inode *);
 extern int ext3_change_inode_journal_flag(struct inode *, int);
 extern void ext3_truncate (struct inode *);
--- diff/include/linux/ext3_fs_i.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/ext3_fs_i.h	2004-05-27 18:34:19.000000000 +0100
@@ -18,8 +18,16 @@
 
 #include <linux/rwsem.h>
 
+struct reserve_window {
+	struct list_head 	rsv_list;
+	__u32			rsv_start;
+	__u32			rsv_end;
+	atomic_t		rsv_goal_size;
+	__u32			rsv_alloc_hit;
+};
+
 /*
- * second extended file system inode data in memory
+ * third extended file system inode data in memory
  */
 struct ext3_inode_info {
 	__u32	i_data[15];
@@ -57,10 +65,9 @@
 	 * allocation when we detect linearly ascending requests.
 	 */
 	__u32	i_next_alloc_goal;
-#ifdef EXT3_PREALLOCATE
-	__u32	i_prealloc_block;
-	__u32	i_prealloc_count;
-#endif
+	/* block reservation window */
+	struct reserve_window i_rsv_window;
+
 	__u32	i_dir_start_lookup;
 #ifdef CONFIG_EXT3_FS_XATTR
 	/*
--- diff/include/linux/ext3_fs_sb.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/ext3_fs_sb.h	2004-05-27 18:34:19.000000000 +0100
@@ -59,6 +59,10 @@
 	struct percpu_counter s_dirs_counter;
 	struct blockgroup_lock s_blockgroup_lock;
 
+	/* head of the per fs reservation window tree */
+	spinlock_t s_rsv_window_lock;
+	struct reserve_window s_rsv_window_head;
+
 	/* Journaling */
 	struct inode * s_journal_inode;
 	struct journal_s * s_journal;
--- diff/include/linux/fs.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/fs.h	2004-05-27 18:34:19.000000000 +0100
@@ -13,15 +13,12 @@
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 #include <linux/ioctl.h>
-#include <linux/list.h>
 #include <linux/dcache.h>
 #include <linux/stat.h>
 #include <linux/cache.h>
-#include <linux/radix-tree.h>
 #include <linux/prio_tree.h>
 #include <linux/kobject.h>
 #include <asm/atomic.h>
-#include <linux/audit.h>
 
 struct iovec;
 struct nameidata;
@@ -86,6 +83,7 @@
 #define SPECIAL 4	/* For non-blockdevice requests in request queue */
 #define READ_SYNC	(READ | (1 << BIO_RW_SYNC))
 #define WRITE_SYNC	(WRITE | (1 << BIO_RW_SYNC))
+#define WRITE_BARRIER	((1 << BIO_RW) | (1 << BIO_RW_BARRIER))
 
 #define SEL_IN		1
 #define SEL_OUT		2
@@ -214,6 +212,9 @@
 
 #ifdef __KERNEL__
 
+#include <linux/list.h>
+#include <linux/radix-tree.h>
+#include <linux/audit.h>
 #include <asm/semaphore.h>
 #include <asm/byteorder.h>
 
@@ -326,7 +327,7 @@
 struct address_space {
 	struct inode		*host;		/* owner: inode, block_device */
 	struct radix_tree_root	page_tree;	/* radix tree of all pages */
-	spinlock_t		tree_lock;	/* and spinlock protecting it */
+	rwlock_t		tree_lock;	/* and rwlock protecting it */
 	unsigned long		nrpages;	/* number of total pages */
 	pgoff_t			writeback_index;/* writeback starts here */
 	struct address_space_operations *a_ops;	/* methods */
@@ -411,6 +412,7 @@
 struct inode {
 	struct hlist_node	i_hash;
 	struct list_head	i_list;
+	struct list_head	i_sb_list;
 	struct list_head	i_dentry;
 	unsigned long		i_ino;
 	atomic_t		i_count;
@@ -532,8 +534,8 @@
 	rwlock_t lock;          /* protects pid, uid, euid fields */
 	int pid;		/* pid or -pgrp where SIGIO should be sent */
 	uid_t uid, euid;	/* uid/euid of process setting the owner */
-	int signum;		/* posix.1b rt signal to be delivered on IO */
 	void *security;
+	int signum;		/* posix.1b rt signal to be delivered on IO */
 };
 
 /*
@@ -561,10 +563,10 @@
 	atomic_t		f_count;
 	unsigned int 		f_flags;
 	mode_t			f_mode;
+	int			f_error;
 	loff_t			f_pos;
 	struct fown_struct	f_owner;
 	unsigned int		f_uid, f_gid;
-	int			f_error;
 	struct file_ra_state	f_ra;
 
 	unsigned long		f_version;
@@ -744,6 +746,7 @@
 	atomic_t		s_active;
 	void                    *s_security;
 
+	struct list_head	s_inodes;	/* all inodes */
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_io;		/* parked for writeback */
 	struct hlist_head	s_anon;		/* anonymous dentries for (nfs) exporting */
@@ -900,6 +903,7 @@
 			struct inode *, struct dentry *);
 	int (*readlink) (struct dentry *, char __user *,int);
 	int (*follow_link) (struct dentry *, struct nameidata *);
+	void (*put_link) (struct dentry *, struct nameidata *);
 	void (*truncate) (struct inode *);
 	int (*permission) (struct inode *, int, struct nameidata *);
 	int (*setattr) (struct dentry *, struct iattr *);
@@ -1459,12 +1463,17 @@
 
 #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
 
+extern void nd_set_link(struct nameidata *, char *);
+extern char *nd_get_link(struct nameidata *);
 extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
 extern int vfs_follow_link(struct nameidata *, const char *);
 extern int page_readlink(struct dentry *, char __user *, int);
 extern int page_follow_link(struct dentry *, struct nameidata *);
+extern int page_follow_link_light(struct dentry *, struct nameidata *);
+extern void page_put_link(struct dentry *, struct nameidata *);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern struct inode_operations page_symlink_inode_operations;
+extern int generic_readlink(struct dentry *, char __user *, int);
 extern void generic_fillattr(struct inode *, struct kstat *);
 extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 void inode_add_bytes(struct inode *inode, loff_t bytes);
--- diff/include/linux/futex.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/futex.h	2004-05-27 18:34:19.000000000 +0100
@@ -8,9 +8,10 @@
 #define FUTEX_WAKE (1)
 #define FUTEX_FD (2)
 #define FUTEX_REQUEUE (3)
-
+#define FUTEX_CMP_REQUEUE (4)
 
 long do_futex(unsigned long uaddr, int op, int val,
-		unsigned long timeout, unsigned long uaddr2, int val2);
+		unsigned long timeout, unsigned long uaddr2, int val2,
+		int val3);
 
 #endif
--- diff/include/linux/ide.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/ide.h	2004-05-27 18:34:19.000000000 +0100
@@ -255,7 +255,7 @@
 		ide_pdc4030,	ide_rz1000,	ide_trm290,
 		ide_cmd646,	ide_cy82c693,	ide_4drives,
 		ide_pmac,	ide_etrax100,	ide_acorn,
-		ide_pc9800,	ide_forced
+		ide_forced
 } hwif_chipset_t;
 
 /*
@@ -309,7 +309,7 @@
  * ide_init_hwif_ports() is OBSOLETE and will be removed in 2.7 series.
  * New ports shouldn't define IDE_ARCH_OBSOLETE_INIT in <asm/ide.h>.
  *
- * m68k, m68knommu (broken) and i386-pc9800 (broken)
+ * m68k and m68knommu (broken)
  * still have their own versions.
  */
 #ifndef CONFIG_M68K
@@ -773,6 +773,7 @@
 	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
 	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
 	u8	queue_depth;	/* max queue depth */
+	u8	doing_barrier;	/* state, 1=currently doing flush */
 
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
@@ -1008,6 +1009,7 @@
 	unsigned dma;
 
 	void (*led_act)(void *data, int rw);
+	unsigned int (*max_rqsize)(ide_drive_t *);
 } ide_hwif_t;
 
 /*
@@ -1304,6 +1306,11 @@
 extern void ide_init_drive_cmd (struct request *rq);
 
 /*
+ * this function returns error location sector offset in case of a write error
+ */
+extern u64 ide_get_error_location(ide_drive_t *, char *);
+
+/*
  * "action" parameter type for ide_do_drive_cmd() below.
  */
 typedef enum {
@@ -1708,4 +1715,11 @@
 
 extern struct bus_type ide_bus_type;
 
+/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
+#define ide_id_has_flush_cache(id)	((id)->cfs_enable_2 & 0x3000)
+
+/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */
+#define ide_id_has_flush_cache_ext(id)	\
+	(((id)->cfs_enable_2 & 0x2400) == 0x2400)
+
 #endif /* _IDE_H */
--- diff/include/linux/idr.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/idr.h	2004-05-27 18:34:19.000000000 +0100
@@ -11,14 +11,20 @@
 #include <linux/types.h>
 #include <asm/bitops.h>
 
-#define RESERVED_ID_BITS 8
-
 #if BITS_PER_LONG == 32
 # define IDR_BITS 5
-# define IDR_FULL 0xffffffff
+# define IDR_FULL 0xfffffffful
+/* We can only use two of the bits in the top level because there is
+   only one possible bit in the top level (5 bits * 7 levels = 35
+   bits, but you only use 31 bits in the id). */
+# define TOP_LEVEL_FULL (IDR_FULL >> 30)
 #elif BITS_PER_LONG == 64
 # define IDR_BITS 6
-# define IDR_FULL 0xffffffffffffffff
+# define IDR_FULL 0xfffffffffffffffful
+/* We can only use two of the bits in the top level because there is
+   only one possible bit in the top level (6 bits * 6 levels = 36
+   bits, but you only use 31 bits in the id). */
+# define TOP_LEVEL_FULL (IDR_FULL >> 62)
 #else
 # error "BITS_PER_LONG is not 32 or 64"
 #endif
@@ -26,11 +32,8 @@
 #define IDR_SIZE (1 << IDR_BITS)
 #define IDR_MASK ((1 << IDR_BITS)-1)
 
-/* Define the size of the id's */
-#define BITS_PER_INT (sizeof(int)*8)
-
-#define MAX_ID_SHIFT (BITS_PER_INT - RESERVED_ID_BITS)
-#define MAX_ID_BIT (1 << MAX_ID_SHIFT)
+#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
 #define MAX_ID_MASK (MAX_ID_BIT - 1)
 
 /* Leave the possibility of an incomplete final layer */
@@ -40,25 +43,23 @@
 #define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
 
 struct idr_layer {
-	unsigned long		 bitmap;	/* A zero bit means "space here" */
+	unsigned long		 bitmap; /* A zero bit means "space here" */
 	struct idr_layer	*ary[1<<IDR_BITS];
-	int			 count;		/* When zero, we can release it */
+	int			 count;	 /* When zero, we can release it */
 };
 
 struct idr {
 	struct idr_layer *top;
 	struct idr_layer *id_free;
-	long		  count;
 	int		  layers;
 	int		  id_free_cnt;
 	spinlock_t	  lock;
 };
 
-#define IDR_INIT(name)	\
+#define IDR_INIT(name)						\
 {								\
 	.top		= NULL,					\
 	.id_free	= NULL,					\
-	.count		= 0,					\
 	.layers 	= 0,					\
 	.id_free_cnt	= 0,					\
 	.lock		= SPIN_LOCK_UNLOCKED,			\
@@ -71,9 +72,9 @@
 
 void *idr_find(struct idr *idp, int id);
 int idr_pre_get(struct idr *idp, unsigned gfp_mask);
-int idr_get_new(struct idr *idp, void *ptr);
+int idr_get_new(struct idr *idp, void *ptr, int *id);
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
 void idr_remove(struct idr *idp, int id);
 void idr_init(struct idr *idp);
 
 extern kmem_cache_t *idr_layer_cache;
-
--- diff/include/linux/init.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/init.h	2004-05-27 18:34:19.000000000 +0100
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 #include <linux/compiler.h>
+#include <asm/setup.h>
 
 /* These macros are used to mark some functions or 
  * initialized data (doesn't apply to uninitialized data)
@@ -66,6 +67,9 @@
 
 extern initcall_t __con_initcall_start, __con_initcall_end;
 extern initcall_t __security_initcall_start, __security_initcall_end;
+
+/* Defined in init/main.c */
+extern char saved_command_line[COMMAND_LINE_SIZE];
 #endif
   
 #ifndef MODULE
@@ -107,25 +111,33 @@
 struct obs_kernel_param {
 	const char *str;
 	int (*setup_func)(char *);
+	int early;
 };
 
-/* OBSOLETE: see moduleparam.h for the right way. */
-#define __setup_param(str, unique_id, fn)			\
+/* Only for really core code.  See moduleparam.h for the normal way. */
+#define __setup_param(str, unique_id, fn, early)			\
 	static char __setup_str_##unique_id[] __initdata = str;	\
 	static struct obs_kernel_param __setup_##unique_id	\
 		 __attribute_used__				\
 		 __attribute__((__section__(".init.setup")))	\
-		= { __setup_str_##unique_id, fn }
+		= { __setup_str_##unique_id, fn, early }
 
 #define __setup_null_param(str, unique_id)			\
-	__setup_param(str, unique_id, NULL)
+	__setup_param(str, unique_id, NULL, 0)
 
 #define __setup(str, fn)					\
-	__setup_param(str, fn, fn)
+	__setup_param(str, fn, fn, 0)
 
 #define __obsolete_setup(str)					\
 	__setup_null_param(str, __LINE__)
 
+/* NOTE: fn is as per module_param, not __setup!  Emits warning if fn
+ * returns non-zero. */
+#define early_param(str, fn)					\
+	__setup_param(str, fn, fn, 1)
+
+/* Relies on saved_command_line being set */
+void __init parse_early_param(void);
 #endif /* __ASSEMBLY__ */
 
 /**
--- diff/include/linux/input.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/input.h	2004-05-27 18:34:19.000000000 +0100
@@ -655,7 +655,7 @@
 	struct ff_envelope envelope;
 
 /* Only used if waveform == FF_CUSTOM */
-	__u32 custom_len;	/* Number of samples  */	
+	__u32 custom_len;	/* Number of samples */
 	__s16 *custom_data;	/* Buffer of samples */
 /* Note: the data pointed by custom_data is copied by the driver. You can
  * therefore dispose of the memory after the upload/update */
@@ -749,8 +749,6 @@
 #define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
 	((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
 
-#define init_input_dev(dev)	do { INIT_LIST_HEAD(&((dev)->h_list)); INIT_LIST_HEAD(&((dev)->node)); } while (0)
-
 #define SET_INPUT_KEYCODE(dev, scancode, val)			\
 		({	unsigned __old;				\
 		switch (dev->keycodesize) {			\
@@ -915,6 +913,12 @@
 #define to_handle(n) container_of(n,struct input_handle,d_node)
 #define to_handle_h(n) container_of(n,struct input_handle,h_node)
 
+static inline void init_input_dev(struct input_dev *dev)
+{
+	INIT_LIST_HEAD(&dev->h_list);
+	INIT_LIST_HEAD(&dev->node);
+}
+
 void input_register_device(struct input_dev *);
 void input_unregister_device(struct input_dev *);
 
@@ -932,14 +936,51 @@
 
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 
-#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c))
-#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c)
-#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c)
-#define input_report_ff(a,b,c)	input_event(a, EV_FF, b, c)
-#define input_report_ff_status(a,b,c)	input_event(a, EV_FF_STATUS, b, c)
+static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
+{
+	input_event(dev, EV_KEY, code, !!value);
+}
+
+static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
+{
+	input_event(dev, EV_REL, code, value);
+}
+
+static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
+{
+	input_event(dev, EV_ABS, code, value);
+}
+
+static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value)
+{
+	input_event(dev, EV_FF, code, value);
+}
+
+static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
+{
+	input_event(dev, EV_FF_STATUS, code, value);
+}
+
+static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
+{
+	dev->regs = regs;
+}
+
+static inline void input_sync(struct input_dev *dev)
+{
+	input_event(dev, EV_SYN, SYN_REPORT, 0);
+	dev->regs = NULL;
+}
+
+static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
+{
+	dev->absmin[axis] = min;
+	dev->absmax[axis] = max;
+	dev->absfuzz[axis] = fuzz;
+	dev->absflat[axis] = flat;
 
-#define input_regs(a,b)		do { (a)->regs = (b); } while (0)
-#define input_sync(a)		do { input_event(a, EV_SYN, SYN_REPORT, 0); (a)->regs = NULL; } while (0)
+	dev->absbit[LONG(axis)] |= BIT(axis);
+}
 
 extern struct class_simple *input_class;
 
--- diff/include/linux/jbd.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/jbd.h	2004-05-27 18:34:19.000000000 +0100
@@ -840,6 +840,7 @@
 #define JFS_ACK_ERR	0x004	/* The errno in the sb has been acked */
 #define JFS_FLUSHED	0x008	/* The journal superblock has been flushed */
 #define JFS_LOADED	0x010	/* The journal superblock has been loaded */
+#define JFS_BARRIER	0x020	/* Use IDE barriers */
 
 /* 
  * Function declarations for the journaling transaction and buffer
@@ -1006,6 +1007,7 @@
 int log_start_commit(journal_t *journal, tid_t tid);
 int __log_start_commit(journal_t *journal, tid_t tid);
 int journal_start_commit(journal_t *journal, tid_t *tid);
+int journal_force_commit_nested(journal_t *journal);
 int log_wait_commit(journal_t *journal, tid_t tid);
 int log_do_checkpoint(journal_t *journal);
 
--- diff/include/linux/kernel.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/kernel.h	2004-05-27 18:34:19.000000000 +0100
@@ -61,7 +61,6 @@
 	ATTRIB_NORET;
 NORET_TYPE void complete_and_exit(struct completion *, long)
 	ATTRIB_NORET;
-extern int abs(int);
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
@@ -80,6 +79,8 @@
 	__attribute__ ((format (scanf,2,3)));
 extern int vsscanf(const char *, const char *, va_list);
 
+extern void qsort(void *, size_t, size_t, int (*)(const void *,const void *));
+
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);
 extern unsigned long long memparse(char *ptr, char **retptr);
@@ -106,6 +107,13 @@
 		console_loglevel = 15;
 }
 
+static inline int abs(int x)
+{
+	if (x < 0)
+		return -x;
+	return x;
+}
+
 extern void bust_spinlocks(int yes);
 extern int oops_in_progress;		/* If set, an oops, panic(), BUG() or die() is in progress */
 extern int panic_on_oops;
--- diff/include/linux/kmalloc_sizes.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/kmalloc_sizes.h	2004-05-27 18:34:19.000000000 +0100
@@ -12,6 +12,9 @@
 	CACHE(256)
 	CACHE(512)
 	CACHE(1024)
+#if (PAGE_SIZE != 4096)	/* special cache for eth skbs - 5 fit into one 8 kB page */
+	CACHE(1620)
+#endif
 	CACHE(2048)
 	CACHE(4096)
 	CACHE(8192)
--- diff/include/linux/list.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/list.h	2004-05-27 18:34:19.000000000 +0100
@@ -158,8 +158,11 @@
  * Note: list_empty on entry does not return true after this, the entry is
  * in an undefined state.
  */
+#include <linux/kernel.h>	/* BUG_ON */
 static inline void list_del(struct list_head *entry)
 {
+	BUG_ON(entry->prev->next != entry);
+	BUG_ON(entry->next->prev != entry);
 	__list_del(entry->prev, entry->next);
 	entry->next = LIST_POISON1;
 	entry->prev = LIST_POISON2;
--- diff/include/linux/major.h	2004-05-19 22:13:01.000000000 +0100
+++ source/include/linux/major.h	2004-05-27 18:34:19.000000000 +0100
@@ -165,4 +165,6 @@
 
 #define VIOTAPE_MAJOR		230
 
+#define HPET_MAJOR		229	/* High Precision Event Timer */
+
 #endif
--- diff/include/linux/mm.h	2004-05-27 13:41:26.000000000 +0100
+++ source/include/linux/mm.h	2004-05-27 18:34:19.000000000 +0100
@@ -189,13 +189,6 @@
  * it to keep track of whatever it is we are using the page for at the
  * moment. Note that we have no way to track which tasks are using
  * a page.
- *
- * Try to keep the most commonly accessed fields in single cache lines
- * here (16 bytes or greater).  This ordering should be particularly
- * beneficial on 32-bit processors.
- *
- * The first line is data used in page cache lookup, the second line
- * is used for linear searches (eg. clock algorithm scans). 
  */
 struct page {
 	page_flags_t flags;		/* Atomic flags, some possibly
--- diff/include/linux/mqueue.h	2004-05-19 22:13:01.000000000 +0100
+++ source/include/linux/mqueue.h	2004-05-27 18:34:19.000000000 +0100
@@ -21,6 +21,8 @@
 #include <linux/types.h>
 
 #define MQ_PRIO_MAX 	32768
+/* per-uid limit of kernel memory used by mqueue, in bytes */
+#define MQ_BYTES_MAX	819200
 
 struct mq_attr {
 	long	mq_flags;	/* message queue flags			*/
--- diff/include/linux/namei.h	2004-05-19 22:13:01.000000000 +0100
+++ source/include/linux/namei.h	2004-05-27 18:34:19.000000000 +0100
@@ -10,12 +10,15 @@
 	int	create_mode;
 };
 
+enum { MAX_NESTED_LINKS = 5 };
+
 struct nameidata {
 	struct dentry	*dentry;
 	struct vfsmount *mnt;
 	struct qstr	last;
 	unsigned int	flags;
 	int		last_type;
+	char *saved_names[MAX_NESTED_LINKS + 1];
 
 	/* Intent data */
 	union {
--- diff/include/linux/pci_ids.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/pci_ids.h	2004-05-27 18:34:19.000000000 +0100
@@ -1648,8 +1648,8 @@
 #define PCI_SUBDEVICE_ID_CHASE_PCIRAS8		0xF010
 
 #define PCI_VENDOR_ID_AUREAL		0x12eb
-#define PCI_DEVICE_ID_AUREAL_VORTEX	0x0001
-#define PCI_DEVICE_ID_AUREAL_VORTEX2	0x0002
+#define PCI_DEVICE_ID_AUREAL_VORTEX_1	0x0001
+#define PCI_DEVICE_ID_AUREAL_VORTEX_2	0x0002
 #define PCI_DEVICE_ID_AUREAL_ADVANTAGE	0x0003
 
 #define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8
@@ -1763,6 +1763,8 @@
 
 #define PCI_VENDOR_ID_3WARE		0x13C1
 #define PCI_DEVICE_ID_3WARE_1000	0x1000
+#define PCI_DEVICE_ID_3WARE_7000	0x1001
+#define PCI_DEVICE_ID_3WARE_9000	0x1002
 
 #define PCI_VENDOR_ID_IOMEGA		0x13ca
 #define PCI_DEVICE_ID_IOMEGA_BUZ	0x4231
@@ -1875,6 +1877,11 @@
 #define PCI_VENDOR_ID_ZOLTRIX		0x15b0
 #define PCI_DEVICE_ID_ZOLTRIX_2BD0	0x2bd0 
 
+#define PCI_VENDOR_ID_MELLANOX		0x15b3
+#define PCI_DEVICE_ID_MELLANOX_TAVOR	0x5a44
+#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
+#define PCI_DEVICE_ID_MELLANOX_ARBEL	0x6282
+
 #define PCI_VENDOR_ID_PDC		0x15e9
 #define PCI_DEVICE_ID_PDC_1841		0x1841
 
@@ -1896,6 +1903,8 @@
 #define	PCI_DEVICE_ID_S2IO_WIN		0x5731
 #define	PCI_DEVICE_ID_S2IO_UNI		0x5831
 
+#define PCI_VENDOR_ID_TOPSPIN		0x1867
+
 #define PCI_VENDOR_ID_ARC               0x192E
 #define PCI_DEVICE_ID_ARC_EHCI          0x0101
 
@@ -1987,6 +1996,7 @@
 #define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
 #define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
 #define PCI_DEVICE_ID_INTEL_7116	0x1223
+#define PCI_DEVICE_ID_INTEL_7501_0	0x254c
 #define PCI_DEVICE_ID_INTEL_7505_0	0x2550  
 #define PCI_DEVICE_ID_INTEL_7505_1	0x2552  
 #define PCI_DEVICE_ID_INTEL_7205_0	0x255d
--- diff/include/linux/rcupdate.h	2004-05-19 22:13:02.000000000 +0100
+++ source/include/linux/rcupdate.h	2004-05-27 18:34:19.000000000 +0100
@@ -41,6 +41,7 @@
 #include <linux/threads.h>
 #include <linux/percpu.h>
 #include <linux/cpumask.h>
+#include <linux/seqlock.h>
 
 /**
  * struct rcu_head - callback structure for use with RCU
@@ -63,14 +64,13 @@
 
 
 
-/* Control variables for rcupdate callback mechanism. */
+/* Global control variables for rcupdate callback mechanism. */
 struct rcu_ctrlblk {
-	spinlock_t	mutex;		/* Guard this struct                  */
-	long		curbatch;	/* Current batch number.	      */
-	long		maxbatch;	/* Max requested batch number.        */
-	cpumask_t	rcu_cpu_mask; 	/* CPUs that need to switch in order  */
-					/* for current batch to proceed.      */
-};
+	long	cur;		/* Current batch number.                      */
+	long	completed;	/* Number of the last completed batch         */
+	int	next_pending;	/* Is the next batch already waiting?         */
+	seqcount_t lock;	/* For atomic reads of cur and next_pending.  */
+} ____cacheline_maxaligned_in_smp;
 
 /* Is batch a before batch b ? */
 static inline int rcu_batch_before(long a, long b)
@@ -90,9 +90,14 @@
  * curlist - current batch for which quiescent cycle started if any
  */
 struct rcu_data {
+	/* 1) quiescent state handling : */
+        long		quiescbatch;     /* Batch # for grace period */
 	long		qsctr;		 /* User-mode/idle loop etc. */
         long            last_qsctr;	 /* value of qsctr at beginning */
                                          /* of rcu grace period */
+	int		qs_pending;	 /* core waits for quiesc state */
+
+	/* 2) batch handling */
         long  	       	batch;           /* Batch # for current RCU batch */
         struct list_head  nxtlist;
         struct list_head  curlist;
@@ -101,24 +106,31 @@
 DECLARE_PER_CPU(struct rcu_data, rcu_data);
 extern struct rcu_ctrlblk rcu_ctrlblk;
 
+#define RCU_quiescbatch(cpu)	(per_cpu(rcu_data, (cpu)).quiescbatch)
 #define RCU_qsctr(cpu) 		(per_cpu(rcu_data, (cpu)).qsctr)
 #define RCU_last_qsctr(cpu) 	(per_cpu(rcu_data, (cpu)).last_qsctr)
+#define RCU_qs_pending(cpu)	(per_cpu(rcu_data, (cpu)).qs_pending)
 #define RCU_batch(cpu) 		(per_cpu(rcu_data, (cpu)).batch)
 #define RCU_nxtlist(cpu) 	(per_cpu(rcu_data, (cpu)).nxtlist)
 #define RCU_curlist(cpu) 	(per_cpu(rcu_data, (cpu)).curlist)
 
-#define RCU_QSCTR_INVALID	0
-
 static inline int rcu_pending(int cpu) 
 {
-	if ((!list_empty(&RCU_curlist(cpu)) &&
-	     rcu_batch_before(RCU_batch(cpu), rcu_ctrlblk.curbatch)) ||
-	    (list_empty(&RCU_curlist(cpu)) &&
-			 !list_empty(&RCU_nxtlist(cpu))) ||
-	    cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask))
+	/* This cpu has pending rcu entries and the grace period
+	 * for them has completed.
+	 */
+	if (!list_empty(&RCU_curlist(cpu)) &&
+		  !rcu_batch_before(rcu_ctrlblk.completed,RCU_batch(cpu)))
+		return 1;
+	/* This cpu has no pending entries, but there are new entries */
+	if (list_empty(&RCU_curlist(cpu)) &&
+			 !list_empty(&RCU_nxtlist(cpu)))
+		return 1;
+	/* The rcu core waits for a quiescent state from the cpu */
+	if (RCU_quiescbatch(cpu) != rcu_ctrlblk.cur || RCU_qs_pending(cpu))
 		return 1;
-	else
-		return 0;
+	/* nothing to do */
+	return 0;
 }
 
 #define rcu_read_lock()		preempt_disable()
@@ -126,6 +138,7 @@
 
 extern void rcu_init(void);
 extern void rcu_check_callbacks(int cpu, int user);
+extern void rcu_restart_cpu(int cpu);
 
 /* Exported interfaces */
 extern void FASTCALL(call_rcu(struct rcu_head *head, 
--- diff/include/linux/reiserfs_fs.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/reiserfs_fs.h	2004-05-27 18:34:19.000000000 +0100
@@ -1238,8 +1238,12 @@
 gods only know how we are going to SMP the code that uses them.
 znodes are the way! */
 
+#define PATH_READA	0x1 /* do read ahead */
+#define PATH_READA_BACK 0x2 /* read backwards */
+
 struct  path {
   int                   path_length;                      	/* Length of the array above.   */
+  int			reada;
   struct  path_element  path_elements[EXTENDED_MAX_HEIGHT];	/* Array of the path elements.  */
   int			pos_in_item;
 };
@@ -1247,7 +1251,7 @@
 #define pos_in_item(path) ((path)->pos_in_item)
 
 #define INITIALIZE_PATH(var) \
-struct path var = {ILLEGAL_PATH_ELEMENT_OFFSET, }
+struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
 
 /* Get path element by path and path position. */
 #define PATH_OFFSET_PELEMENT(p_s_path,n_offset)  ((p_s_path)->path_elements +(n_offset))
@@ -1748,6 +1752,14 @@
 int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh);
 int journal_mark_dirty(struct reiserfs_transaction_handle *, struct super_block *, struct buffer_head *bh) ;
 
+static inline int
+reiserfs_file_data_log(struct inode *inode) {
+    if (reiserfs_data_log(inode->i_sb) ||
+       (REISERFS_I(inode)->i_flags & i_data_log))
+        return 1 ;
+    return 0 ;
+}
+
 static inline int reiserfs_transaction_running(struct super_block *s) {
     struct reiserfs_transaction_handle *th = current->journal_info ;
     if (th && th->t_super == s)
@@ -1765,7 +1777,8 @@
 int reiserfs_commit_page(struct inode *inode, struct page *page,
 		unsigned from, unsigned to);
 int reiserfs_flush_old_commits(struct super_block *);
-void reiserfs_commit_for_inode(struct inode *) ;
+int reiserfs_commit_for_inode(struct inode *) ;
+int  reiserfs_inode_needs_commit(struct inode *) ;
 void reiserfs_update_inode_transaction(struct inode *) ;
 void reiserfs_wait_on_write_block(struct super_block *s) ;
 void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ;
@@ -2149,6 +2162,15 @@
 typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
 
 int reiserfs_parse_alloc_options (struct super_block *, char *);
+void reiserfs_init_alloc_options (struct super_block *s);
+
+/*
+ * given a directory, this will tell you what packing locality
+ * to use for a new object underneat it.  The locality is returned
+ * in disk byte order (le).
+ */
+u32 reiserfs_choose_packing(struct inode *dir);
+
 int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value);
 void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted);
 int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int);
--- diff/include/linux/reiserfs_fs_i.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/reiserfs_fs_i.h	2004-05-27 18:34:19.000000000 +0100
@@ -25,6 +25,7 @@
     i_link_saved_truncate_mask =  0x0020,
     i_priv_object              =  0x0080,
     i_has_xattr_dir            =  0x0100,
+    i_data_log	               =  0x0200,
 } reiserfs_inode_flags;
 
 
--- diff/include/linux/reiserfs_fs_sb.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/reiserfs_fs_sb.h	2004-05-27 18:34:19.000000000 +0100
@@ -444,6 +444,8 @@
     REISERFS_XATTRS,
     REISERFS_XATTRS_USER,
     REISERFS_POSIXACL,
+    REISERFS_BARRIER_NONE,
+    REISERFS_BARRIER_FLUSH,
 
     REISERFS_TEST1,
     REISERFS_TEST2,
@@ -473,6 +475,8 @@
 #define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
 #define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL))
 #define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s))
+#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
+#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
 
 void reiserfs_file_buffer (struct buffer_head * bh, int list);
 extern struct file_system_type reiserfs_fs_type;
--- diff/include/linux/sched.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/sched.h	2004-05-27 18:34:19.000000000 +0100
@@ -96,6 +96,14 @@
 extern unsigned long nr_uninterruptible(void);
 extern unsigned long nr_iowait(void);
 
+#ifdef CONFIG_SCHEDSTATS
+#define schedstat_inc(s, field)		((s)->field++)
+#define schedstat_add(s, field, amt)	((s)->field += amt)
+#else
+#define schedstat_inc(s, field)		do { } while (0)
+#define schedstat_add(d, field, amt)	do { } while (0)
+#endif
+
 #include <linux/time.h>
 #include <linux/param.h>
 #include <linux/resource.h>
@@ -293,7 +301,7 @@
  * in the range MAX_RT_PRIO..MAX_PRIO-1. Priority values
  * are inverted: lower p->prio value means higher priority.
  *
- * The MAX_RT_USER_PRIO value allows the actual maximum
+ * The MAX_USER_RT_PRIO value allows the actual maximum
  * RT priority to be separate from the value exported to
  * user-space.  This allows kernel threads to set their
  * priority to a value higher than any user task. Note:
@@ -314,6 +322,9 @@
 	atomic_t __count;	/* reference count */
 	atomic_t processes;	/* How many processes does this user have? */
 	atomic_t files;		/* How many open files does this user have? */
+	atomic_t sigpending;	/* How many pending signals does this user have? */
+	/* protected by mq_lock	*/
+	unsigned long mq_bytes;	/* How many bytes can be allocated to mqueue? */
 
 	/* Hash table maintenance information */
 	struct list_head uidhash_list;
@@ -347,7 +358,6 @@
 	struct sigqueue *sigq;		/* signal queue entry. */
 };
 
-
 struct io_context;			/* See blkdev.h */
 void exit_io_context(void);
 
@@ -361,6 +371,12 @@
 	gid_t *blocks[0];
 };
 
+/*
+ * get_group_info() must be called with the owning task locked (via task_lock())
+ * when task != current.  The reason being that the vast majority of callers are
+ * looking at current->group_info, which can not be changed except by the
+ * current task.  Changing current->group_info requires the task lock, too.
+ */
 #define get_group_info(group_info) do { \
 	atomic_inc(&(group_info)->usage); \
 } while (0)
@@ -592,6 +608,35 @@
 	unsigned long last_balance;	/* init to jiffies. units in jiffies */
 	unsigned int balance_interval;	/* initialise to 1. units in ms. */
 	unsigned int nr_balance_failed; /* initialise to 0 */
+
+#ifdef CONFIG_SCHEDSTATS
+	unsigned long lb_cnt[3];
+	unsigned long lb_balanced[3];
+	unsigned long lb_failed[3];
+	unsigned long lb_pulled[3];
+	unsigned long lb_hot_pulled[3];
+	unsigned long lb_imbalance[3];
+
+	/* Active load balancing */
+	unsigned long alb_cnt;
+	unsigned long alb_failed;
+	unsigned long alb_pushed;
+
+	/* Wakeups */
+	unsigned long sched_wake_remote;
+
+	/* Passive load balancing */
+	unsigned long plb_pulled;
+
+	/* Affine wakeups */
+	unsigned long afw_pulled;
+
+	/* SD_BALANCE_EXEC balances */
+	unsigned long sbe_pushed;
+
+	/* SD_BALANCE_CLONE balances */
+	unsigned long sbc_pushed;
+#endif
 };
 
 /* Common values for SMT siblings */
@@ -719,6 +764,11 @@
 
 /* per-UID process charging. */
 extern struct user_struct * alloc_uid(uid_t);
+static inline struct user_struct *get_uid(struct user_struct *u)
+{
+	atomic_inc(&u->__count);
+	return u;
+}
 extern void free_uid(struct user_struct *);
 extern void switch_uid(struct user_struct *);
 
@@ -922,7 +972,9 @@
 extern void unhash_process(struct task_struct *p);
 
 /*
- * Protects ->fs, ->files, ->mm, ->ptrace and synchronises with wait4().
+ * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info and synchronises with
+ * wait4().
+ *
  * Nests both inside and outside of read_lock(&tasklist_lock).
  * It must not be nested with write_lock_irq(&tasklist_lock),
  * neither inside nor outside.
@@ -1008,6 +1060,7 @@
 extern void __cond_resched(void);
 static inline void cond_resched(void)
 {
+	might_sleep();
 	if (need_resched())
 		__cond_resched();
 }
--- diff/include/linux/serial_core.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/serial_core.h	2004-05-27 18:34:19.000000000 +0100
@@ -59,14 +59,6 @@
 /* NEC v850.  */
 #define PORT_V850E_UART	40
 
-/* NEC PC-9800 */
-#define PORT_8251_PC98	41
-#define PORT_19K_PC98	42
-#define PORT_FIFO_PC98	43
-#define PORT_VFAST_PC98	44
-#define PORT_PC9861	45
-#define PORT_PC9801_101	46
-
 /* DZ */
 #define PORT_DZ		47
 
@@ -171,7 +163,9 @@
 	unsigned char		x_char;			/* xon/xoff char */
 	unsigned char		regshift;		/* reg offset shift */
 	unsigned char		iotype;			/* io access style */
-
+#ifdef CONFIG_KGDB
+	int			kgdb;			/* in use by kgdb */
+#endif
 #define UPIO_PORT		(0)
 #define UPIO_HUB6		(1)
 #define UPIO_MEM		(2)
--- diff/include/linux/serio.h	2004-05-19 22:13:02.000000000 +0100
+++ source/include/linux/serio.h	2004-05-27 18:34:19.000000000 +0100
@@ -105,7 +105,6 @@
 #define SERIO_8042	0x01000000UL
 #define SERIO_RS232	0x02000000UL
 #define SERIO_HIL_MLC	0x03000000UL
-#define SERIO_PC9800	0x04000000UL
 #define SERIO_PS_PSTHRU	0x05000000UL
 #define SERIO_8042_XL	0x06000000UL
 
--- diff/include/linux/signal.h	2004-05-19 22:13:02.000000000 +0100
+++ source/include/linux/signal.h	2004-05-27 18:34:19.000000000 +0100
@@ -7,6 +7,9 @@
 #include <asm/siginfo.h>
 
 #ifdef __KERNEL__
+
+#define MAX_SIGPENDING	1024
+
 /*
  * Real Time signals may be queued.
  */
@@ -16,6 +19,7 @@
 	spinlock_t *lock;
 	int flags;
 	siginfo_t info;
+	struct user_struct *user;
 };
 
 /* flags values. */
--- diff/include/linux/spinlock.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/spinlock.h	2004-05-27 18:34:19.000000000 +0100
@@ -15,6 +15,12 @@
 
 #include <asm/processor.h>	/* for cpu relax */
 #include <asm/system.h>
+#ifdef CONFIG_KGDB
+#include <asm/current.h>
+#define SET_WHO(x, him) (x)->who = him;
+#else
+#define SET_WHO(x, him)
+#endif
 
 /*
  * Must define these before including other files, inline functions need them
@@ -57,6 +63,9 @@
 	const char *module;
 	char *owner;
 	int oline;
+#ifdef CONFIG_KGDB
+	struct task_struct *who;
+#endif
 } spinlock_t;
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0}
 
@@ -68,6 +77,7 @@
 		(x)->module = __FILE__; \
 		(x)->owner = NULL; \
 		(x)->oline = 0; \
+                SET_WHO(x, NULL) \
 	} while (0)
 
 #define CHECK_LOCK(x) \
@@ -90,6 +100,7 @@
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
 		(x)->oline = __LINE__; \
+                SET_WHO(x, current)       \
 	} while (0)
 
 /* without debugging, spin_is_locked on UP always says
@@ -120,6 +131,7 @@
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
 		(x)->oline = __LINE__; \
+                SET_WHO(x, current)       \
 		1; \
 	})
 
@@ -186,6 +198,17 @@
 
 #endif /* !SMP */
 
+#ifdef CONFIG_LOCKMETER
+extern void _metered_spin_lock   (spinlock_t *lock);
+extern void _metered_spin_unlock (spinlock_t *lock);
+extern int  _metered_spin_trylock(spinlock_t *lock);
+extern void _metered_read_lock    (rwlock_t *lock);
+extern void _metered_read_unlock  (rwlock_t *lock);
+extern void _metered_write_lock   (rwlock_t *lock);
+extern void _metered_write_unlock (rwlock_t *lock);
+extern int  _metered_write_trylock(rwlock_t *lock);
+#endif
+
 /*
  * Define the various spin_lock and rw_lock methods.  Note we define these
  * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various
@@ -391,6 +414,141 @@
 				_raw_spin_trylock(lock) ? 1 : \
 				({preempt_enable(); local_bh_enable(); 0;});})
 
+#ifdef CONFIG_LOCKMETER
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#undef spin_lock_irqsave
+#undef spin_lock_irq
+#undef spin_lock_bh
+#undef read_lock
+#undef read_unlock
+#undef write_lock
+#undef write_unlock
+#undef write_trylock
+#undef spin_unlock_bh
+#undef read_lock_irqsave
+#undef read_lock_irq
+#undef read_lock_bh
+#undef read_unlock_bh
+#undef write_lock_irqsave
+#undef write_lock_irq
+#undef write_lock_bh
+#undef write_unlock_bh
+
+#define spin_lock(lock) \
+do { \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while(0)
+
+#define spin_trylock(lock)     ({preempt_disable(); _metered_spin_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
+#define spin_unlock(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable(); \
+} while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_unlock_bh(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+
+#define read_lock(lock)                ({preempt_disable(); _metered_read_lock(lock);})
+#define read_unlock(lock)      ({_metered_read_unlock(lock); preempt_enable();})
+#define write_lock(lock)       ({preempt_disable(); _metered_write_lock(lock);})
+#define write_unlock(lock)     ({_metered_write_unlock(lock); preempt_enable();})
+#define write_trylock(lock)    ({preempt_disable();_metered_write_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
+#define spin_unlock_no_resched(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable_no_resched(); \
+} while (0)
+
+#define read_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_unlock_bh(lock) \
+do { \
+	_metered_read_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#define write_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_unlock_bh(lock) \
+do { \
+	_metered_write_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#endif /* !CONFIG_LOCKMETER */
+
 /* "lock on reference count zero" */
 #ifndef ATOMIC_DEC_AND_LOCK
 #include <asm/atomic.h>
--- diff/include/linux/sunrpc/cache.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/sunrpc/cache.h	2004-05-27 18:34:19.000000000 +0100
@@ -99,6 +99,7 @@
 	atomic_t		readers;		/* how many time is /chennel open */
 	time_t			last_close;		/* if no readers, when did last close */
 	time_t			last_warn;		/* when we last warned about no readers */
+	void			(*warn_no_listener)(struct cache_detail *cd);
 };
 
 
--- diff/include/linux/syscalls.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/syscalls.h	2004-05-27 18:34:19.000000000 +0100
@@ -256,7 +256,7 @@
 asmlinkage unsigned long sys_mremap(unsigned long addr,
 				unsigned long old_len, unsigned long new_len,
 				unsigned long flags, unsigned long new_addr);
-long sys_remap_file_pages(unsigned long start, unsigned long size,
+asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
 			unsigned long prot, unsigned long pgoff,
 			unsigned long flags);
 asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
--- diff/include/linux/sysfs.h	2004-05-27 13:41:27.000000000 +0100
+++ source/include/linux/sysfs.h	2004-05-27 18:34:19.000000000 +0100
@@ -9,6 +9,8 @@
 #ifndef _SYSFS_H_
 #define _SYSFS_H_
 
+#include <asm/atomic.h>
+
 struct kobject;
 struct module;
 
@@ -47,6 +49,24 @@
 extern int
 sysfs_rename_dir(struct kobject *, const char *new_name);
 
+struct sysfs_dirent {
+	atomic_t		s_count;
+	struct list_head	s_sibling;
+	struct list_head	s_children;
+	void 			* s_element;
+	int			s_type;
+	umode_t			s_mode;
+	struct dentry		* s_dentry;
+};
+
+#define SYSFS_ROOT		0x0001
+#define SYSFS_KOBJECT		0x0002
+#define SYSFS_KOBJ_ATTR 	0x0004
+#define SYSFS_KOBJ_BIN_ATTR	0x0008
+#define SYSFS_KOBJ_ATTR_GROUP	0x0010
+#define SYSFS_KOBJ_LINK 	0x0020
+#define SYSFS_NOT_PINNED	(SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)
+
 extern int
 sysfs_create_file(struct kobject *, const struct attribute *);
 
--- diff/include/linux/writeback.h	2004-05-19 22:13:04.000000000 +0100
+++ source/include/linux/writeback.h	2004-05-27 18:34:19.000000000 +0100
@@ -97,5 +97,6 @@
 extern int nr_pdflush_threads;	/* Global so it can be exported to sysctl
 				   read-only. */
 
+void clear_backing_dev_congested(struct backing_dev_info *bdi, int rw);
 
 #endif		/* WRITEBACK_H */
--- diff/include/pcmcia/ss.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/pcmcia/ss.h	2004-05-27 18:34:19.000000000 +0100
@@ -145,6 +145,7 @@
 	u_int			Attributes;
 	ioaddr_t		BasePort, NumPorts;
 	ioaddr_t		InUse, Config;
+	struct resource		*res;
 } io_window_t;
 
 #define WINDOW_MAGIC	0xB35C
--- diff/include/scsi/scsi_devinfo.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/scsi/scsi_devinfo.h	2004-05-27 18:34:19.000000000 +0100
@@ -4,7 +4,8 @@
  * Flags for SCSI devices that need special treatment
  */
 #define BLIST_NOLUN     	0x001	/* Only scan LUN 0 */
-#define BLIST_FORCELUN  	0x002	/* Known to have LUNs, force scanning */
+#define BLIST_FORCELUN  	0x002	/* Known to have LUNs, force scanning,
+					   deprecated: Use max_luns=N */
 #define BLIST_BORKEN    	0x004	/* Flag for broken handshaking */
 #define BLIST_KEY       	0x008	/* unlock by special command */
 #define BLIST_SINGLELUN 	0x010	/* Do not use LUNs in parallel */
@@ -20,4 +21,7 @@
 #define BLIST_MS_SKIP_PAGE_3F	0x4000	/* do not send ms page 0x3f */
 #define BLIST_USE_10_BYTE_MS	0x8000	/* use 10 byte ms before 6 byte ms */
 #define BLIST_MS_192_BYTES_FOR_3F	0x10000	/*  192 byte ms page 0x3f request */
+#define BLIST_REPORTLUN2	0x20000	/* try REPORT_LUNS even for SCSI-2 devs
+ 					   (if HBA supports more than 8 LUNs) */
+#define BLIST_NOREPORTLUN	0x40000	/* don't try REPORT_LUNS scan (SCSI-3 devs) */
 #endif
--- diff/include/scsi/scsi_driver.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/scsi/scsi_driver.h	2004-05-27 18:34:19.000000000 +0100
@@ -13,6 +13,7 @@
 
 	int (*init_command)(struct scsi_cmnd *);
 	void (*rescan)(struct device *);
+	int (*issue_flush)(struct device *, sector_t *);
 };
 #define to_scsi_driver(drv) \
 	container_of((drv), struct scsi_driver, gendrv)
--- diff/include/sound/ac97_codec.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/sound/ac97_codec.h	2004-05-27 18:34:19.000000000 +0100
@@ -51,7 +51,7 @@
 #define AC97_REC_GAIN_MIC	0x1e	/* Record Gain MIC (optional) */
 #define AC97_GENERAL_PURPOSE	0x20	/* General Purpose (optional) */
 #define AC97_3D_CONTROL		0x22	/* 3D Control (optional) */
-#define AC97_RESERVED		0x24	/* Reserved */
+#define AC97_INT_PAGING		0x24	/* Audio Interrupt & Paging (AC'97 2.3) */
 #define AC97_POWERDOWN		0x26	/* Powerdown control / status */
 /* range 0x28-0x3a - AUDIO AC'97 2.0 extensions */
 #define AC97_EXTENDED_ID	0x28	/* Extended Audio ID */
@@ -82,6 +82,13 @@
 /* range 0x5a-0x7b - Vendor Specific */
 #define AC97_VENDOR_ID1		0x7c	/* Vendor ID1 */
 #define AC97_VENDOR_ID2		0x7e	/* Vendor ID2 / revision */
+/* range 0x60-0x6f (page 1) - extended codec registers */
+#define AC97_CODEC_CLASS_REV	0x60	/* Codec Class/Revision */
+#define AC97_PCI_SVID		0x62	/* PCI Subsystem Vendor ID */
+#define AC97_PCI_SID		0x64	/* PCI Subsystem ID */
+#define AC97_FUNC_SELECT	0x66	/* Function Select */
+#define AC97_FUNC_INFO		0x68	/* Function Information */
+#define AC97_SENSE_INFO		0x6a	/* Sense Details */
 
 /* slot allocation */
 #define AC97_SLOT_TAG		0
@@ -139,6 +146,7 @@
 #define AC97_EI_AMAP		0x0200	/* indicates optional slot/DAC mapping based on codec ID */
 #define AC97_EI_REV_MASK	0x0c00	/* AC'97 revision mask */
 #define AC97_EI_REV_22		0x0400	/* AC'97 revision 2.2 */
+#define AC97_EI_REV_23		0x0800	/* AC'97 revision 2.3 */
 #define AC97_EI_REV_SHIFT	10
 #define AC97_EI_ADDR_MASK	0xc000	/* physical codec ID (address) */
 #define AC97_EI_ADDR_SHIFT	14
@@ -180,6 +188,16 @@
 #define AC97_SC_DRS		0x4000	/* Double Rate S/PDIF */
 #define AC97_SC_V		0x8000	/* Validity status */
 
+/* Interrupt and Paging bit defines (AC'97 2.3) */
+#define AC97_PAGE_MASK		0x000f	/* Page Selector */
+#define AC97_PAGE_VENDOR	0	/* Vendor-specific registers */
+#define AC97_PAGE_1		1	/* Extended Codec Registers page 1 */
+#define AC97_INT_ENABLE		0x0800	/* Interrupt Enable */
+#define AC97_INT_SENSE		0x1000	/* Sense Cycle */
+#define AC97_INT_CAUSE_SENSE	0x2000	/* Sense Cycle Completed (RO) */
+#define AC97_INT_CAUSE_GPIO	0x4000	/* GPIO bits changed (RO) */
+#define AC97_INT_STATUS		0x8000	/* Interrupt Status */
+
 /* extended modem ID bit defines */
 #define AC97_MEI_LINE1		0x0001	/* Line1 present */
 #define AC97_MEI_LINE2		0x0002	/* Line2 present */
--- diff/include/sound/ad1848.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/sound/ad1848.h	2004-05-27 18:34:19.000000000 +0100
@@ -147,9 +147,6 @@
 	int calibrate_mute;
 	int dma_size;
 	int thinkpad_flag;		/* Thinkpad CS4248 needs some extra help */
-#ifdef CONFIG_PM
-	struct pm_dev *thinkpad_pmstate;
-#endif
 
 	spinlock_t reg_lock;
 	struct semaphore open_mutex;
--- diff/include/sound/asound.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/sound/asound.h	2004-05-27 18:34:19.000000000 +0100
@@ -153,7 +153,7 @@
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 6)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 7)
 
 typedef unsigned long sndrv_pcm_uframes_t;
 typedef long sndrv_pcm_sframes_t;
@@ -428,6 +428,22 @@
 	sndrv_pcm_uframes_t avail_min;	/* RW: min available frames for wakeup */
 };
 
+#define SNDRV_PCM_SYNC_PTR_HWSYNC	(1<<0)	/* execute hwsync */
+#define SNDRV_PCM_SYNC_PTR_APPL		(1<<1)	/* get appl_ptr from driver (r/w op) */
+#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN	(1<<2)	/* get avail_min from driver */
+
+struct sndrv_pcm_sync_ptr {
+	unsigned int flags;
+	union {
+		struct sndrv_pcm_mmap_status status;
+		unsigned char reserved[64];
+	} s;
+	union {
+		struct sndrv_pcm_mmap_control control;
+		unsigned char reserved[64];
+	} c;
+};
+
 struct sndrv_xferi {
 	sndrv_pcm_sframes_t result;
 	void *buf;
@@ -451,6 +467,7 @@
 	SNDRV_PCM_IOCTL_STATUS = _IOR('A', 0x20, struct sndrv_pcm_status),
 	SNDRV_PCM_IOCTL_DELAY = _IOR('A', 0x21, sndrv_pcm_sframes_t),
 	SNDRV_PCM_IOCTL_HWSYNC = _IO('A', 0x22),
+	SNDRV_PCM_IOCTL_SYNC_PTR = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr),
 	SNDRV_PCM_IOCTL_CHANNEL_INFO = _IOR('A', 0x32, struct sndrv_pcm_channel_info),
 	SNDRV_PCM_IOCTL_PREPARE = _IO('A', 0x40),
 	SNDRV_PCM_IOCTL_RESET = _IO('A', 0x41),
@@ -538,7 +555,7 @@
  *  Timer section - /dev/snd/timer
  */
 
-#define SNDRV_TIMER_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 1)
+#define SNDRV_TIMER_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 2)
 
 enum sndrv_timer_class {
 	SNDRV_TIMER_CLASS_NONE = -1,
@@ -619,6 +636,7 @@
 
 #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 */
+#define SNDRV_TIMER_PSFLG_EARLY_EVENT	(1<<2)	/* write early event to the poll queue */
 
 struct sndrv_timer_params {
 	unsigned int flags;		/* flags - SNDRV_MIXER_PSFLG_* */
@@ -667,6 +685,7 @@
 	SNDRV_TIMER_EVENT_STOP,			/* val = 0 */
 	SNDRV_TIMER_EVENT_CONTINUE,		/* val = resolution in ns */
 	SNDRV_TIMER_EVENT_PAUSE,		/* val = 0 */
+	SNDRV_TIMER_EVENT_EARLY,		/* val = 0, early event */
 	/* 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,
--- diff/include/sound/core.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/sound/core.h	2004-05-27 18:34:19.000000000 +0100
@@ -163,8 +163,10 @@
 	struct device *dev;
 
 #ifdef CONFIG_PM
-	int (*set_power_state) (snd_card_t *card, unsigned int state);
-	void *power_state_private_data;
+	int (*pm_suspend)(snd_card_t *card, unsigned int state);
+	int (*pm_resume)(snd_card_t *card, unsigned int state);
+	struct pm_dev *pm_dev;		/* for ISA */
+	void *pm_private_data;
 	unsigned int power_state;	/* power state */
 	struct semaphore power_lock;	/* power lock */
 	wait_queue_head_t power_sleep;
@@ -199,12 +201,32 @@
 	card->power_state = state;
 	wake_up(&card->power_sleep);
 }
+int snd_card_set_pm_callback(snd_card_t *card,
+			     int (*suspend)(snd_card_t *, unsigned int),
+			     int (*resume)(snd_card_t *, unsigned int),
+			     void *private_data);
+int snd_card_set_dev_pm_callback(snd_card_t *card, int type,
+				 int (*suspend)(snd_card_t *, unsigned int),
+				 int (*resume)(snd_card_t *, unsigned int),
+				 void *private_data);
+#define snd_card_set_isa_pm_callback(card,suspend,resume,data) \
+	snd_card_set_dev_pm_callback(card, PM_ISA_DEV, suspend, resume, data)
+#ifndef SND_PCI_PM_CALLBACKS
+int snd_card_pci_suspend(struct pci_dev *dev, u32 state);
+int snd_card_pci_resume(struct pci_dev *dev);
+#define SND_PCI_PM_CALLBACKS \
+	.suspend = snd_card_pci_suspend,  .resume = snd_card_pci_resume
+#endif
 #else
 #define snd_power_lock(card)		do { (void)(card); } while (0)
 #define snd_power_unlock(card)		do { (void)(card); } while (0)
 static inline int snd_power_wait(snd_card_t *card, unsigned int state, struct file *file) { return 0; }
 #define snd_power_get_state(card)	SNDRV_CTL_POWER_D0
 #define snd_power_change_state(card, state)	do { (void)(card); } while (0)
+#define snd_card_set_pm_callback(card,suspend,resume,data) -EINVAL
+#define snd_card_set_dev_pm_callback(card,suspend,resume,data) -EINVAL
+#define snd_card_set_isa_pm_callback(card,suspend,resume,data) -EINVAL
+#define SND_PCI_PM_CALLBACKS
 #endif
 
 /* device.c */
--- diff/include/sound/cs4231.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/sound/cs4231.h	2004-05-27 18:34:19.000000000 +0100
@@ -295,7 +295,6 @@
 	void (*set_capture_format) (cs4231_t *chip, snd_pcm_hw_params_t *hw_params, unsigned char cdfr);
 	void (*trigger) (cs4231_t *chip, unsigned int what, int start);
 #ifdef CONFIG_PM
-	struct pm_dev *pm_dev;
 	void (*suspend) (cs4231_t *chip);
 	void (*resume) (cs4231_t *chip);
 #endif
--- diff/include/sound/cs46xx.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/sound/cs46xx.h	2004-05-27 18:34:19.000000000 +0100
@@ -1737,9 +1737,6 @@
 
 	struct snd_cs46xx_gameport *gameport;
 
-#ifdef CONFIG_PM
-	struct pm_dev *pm_dev;
-#endif
 #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
 	int current_gpio;
 #endif
@@ -1771,9 +1768,4 @@
 int snd_cs46xx_start_dsp(cs46xx_t *chip);
 void snd_cs46xx_gameport(cs46xx_t *chip);
 
-#ifdef CONFIG_PM
-void snd_cs46xx_suspend(cs46xx_t *chip);
-void snd_cs46xx_resume(cs46xx_t *chip);
-#endif
-
 #endif /* __SOUND_CS46XX_H */
--- diff/include/sound/emu10k1.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/sound/emu10k1.h	2004-05-27 18:34:19.000000000 +0100
@@ -650,7 +650,8 @@
 #define SPBYPASS_FORMAT		0x00000f00      /* If 1, SPDIF XX uses 24 bit, if 0 - 20 bit	*/
 
 #define AC97SLOT		0x5f            /* additional AC97 slots enable bits		*/
-#define AC97SLOT_10K2		0x03
+#define AC97SLOT_REAR_RIGHT	0x01		/* Rear left */
+#define AC97SLOT_REAR_LEFT	0x02		/* Rear right */
 #define AC97SLOT_CNTR		0x10            /* Center enable */
 #define AC97SLOT_LFE		0x20            /* LFE enable */
 
@@ -937,7 +938,8 @@
 	struct resource *res_port;
 	int APS: 1,				/* APS flag */
 	    no_ac97: 1,				/* no AC'97 */
-	    tos_link: 1;			/* tos link detected */
+	    tos_link: 1,			/* tos link detected */
+	    rear_ac97: 1;			/* rear channels are on AC'97 */
 	unsigned int audigy;			/* is Audigy? */
 	unsigned int revision;			/* chip revision */
 	unsigned int serial;			/* serial number */
@@ -1184,8 +1186,8 @@
 #define EXTOUT_AC97_R	   0x01	/* AC'97 playback channel - right */
 #define EXTOUT_TOSLINK_L   0x02	/* LiveDrive - TOSLink Optical - left */
 #define EXTOUT_TOSLINK_R   0x03	/* LiveDrive - TOSLink Optical - right */
-#define EXTOUT_CENTER      0x04	/* SB Live 5.1 - center */
-#define EXTOUT_LFE         0x05 /* SB Live 5.1 - LFE */
+#define EXTOUT_AC97_CENTER 0x04	/* SB Live 5.1 - center */
+#define EXTOUT_AC97_LFE	   0x05 /* SB Live 5.1 - LFE */
 #define EXTOUT_HEADPHONE_L 0x06	/* LiveDrive - Headphone - left */
 #define EXTOUT_HEADPHONE_R 0x07	/* LiveDrive - Headphone - right */
 #define EXTOUT_REAR_L	   0x08	/* Rear channel - left */
@@ -1193,6 +1195,8 @@
 #define EXTOUT_ADC_CAP_L   0x0a	/* ADC Capture buffer - left */
 #define EXTOUT_ADC_CAP_R   0x0b	/* ADC Capture buffer - right */
 #define EXTOUT_MIC_CAP	   0x0c	/* MIC Capture buffer */
+#define EXTOUT_AC97_REAR_L 0x0d	/* SB Live 5.1 (c) 2003 - Rear Left */
+#define EXTOUT_AC97_REAR_R 0x0e	/* SB Live 5.1 (c) 2003 - Rear Right */
 #define EXTOUT_ACENTER	   0x11 /* Analog Center */
 #define EXTOUT_ALFE	   0x12 /* Analog LFE */
 
--- diff/include/sound/initval.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/sound/initval.h	2004-05-27 18:34:19.000000000 +0100
@@ -133,44 +133,4 @@
 }
 #endif
 
-#if defined(SNDRV_GET_ID) && !defined(MODULE)
-#include <linux/ctype.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-static int __init get_id(char **str, char **dst)
-{
-	char *s;
-
-	if (!(*str) || !(**str))
-		return 0;
-	for (s = *str; isalpha(*s) || isdigit(*s) || *s == '_'; s++);
-	if (s != *str) {
-		int len = s - *str;
-		char *d = (char *)alloc_bootmem(len + 1);
-		if (d != NULL) {
-			memcpy(*dst = d, *str, len);
-			d[len] = '\0';
-		}
-	}
-	if (*s == ',') {
-		*str = s + 1;
-		return 2;
-	}
-	*str = s;
-	return 1;
-}
-#endif
-
-/* simple wrapper for long variable.
- * the value more than 32bit won't work!
- */
-inline static int get_option_long(char **str, long *valp)
-{
-	int val, ret;
-	ret = get_option(str, &val);
-	if (ret)
-		*valp = val;
-	return ret;
-}
-
 #endif /* __SOUND_INITVAL_H */
--- diff/include/sound/timer.h	2004-05-19 22:13:08.000000000 +0100
+++ source/include/sound/timer.h	2004-05-27 18:34:19.000000000 +0100
@@ -60,6 +60,7 @@
 #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_IFLG_EARLY_EVENT 0x00000080	/* write early event to the poll queue */
 
 #define SNDRV_TIMER_FLG_CHANGE	0x00000001
 #define SNDRV_TIMER_FLG_RESCHED	0x00000002	/* need reschedule */
--- diff/include/sound/trident.h	2004-05-19 22:13:08.000000000 +0100
+++ source/include/sound/trident.h	2004-05-27 18:34:19.000000000 +0100
@@ -54,13 +54,6 @@
 #define TRIDENT_DEVICE_ID_NX		((PCI_VENDOR_ID_TRIDENT<<16)|PCI_DEVICE_ID_TRIDENT_4DWAVE_NX)
 #define TRIDENT_DEVICE_ID_SI7018	((PCI_VENDOR_ID_SI<<16)|PCI_DEVICE_ID_SI_7018)
 
-/* Trident chipsets have 1GB memory limit */
-#ifdef __alpha__
-#define TRIDENT_DMA_TYPE        SNDRV_DMA_TYPE_PCI_16MB
-#else
-#define TRIDENT_DMA_TYPE        SNDRV_DMA_TYPE_PCI
-#endif
-
 #define SNDRV_SEQ_DEV_ID_TRIDENT			"trident-synth"
 
 #define SNDRV_TRIDENT_VOICE_TYPE_PCM		0
@@ -488,10 +481,4 @@
 int snd_trident_synth_bzero(trident_t *trident, snd_util_memblk_t *blk, int offset, int size);
 int snd_trident_synth_copy_from_user(trident_t *trident, snd_util_memblk_t *blk, int offset, const char *data, int size);
 
-/* Power Management */
-#ifdef CONFIG_PM
-void snd_trident_suspend(trident_t *trident);
-void snd_trident_resume(trident_t *trident);
-#endif
-
 #endif /* __SOUND_TRIDENT_H */
--- diff/include/sound/uda1341.h	2004-05-19 22:13:08.000000000 +0100
+++ source/include/sound/uda1341.h	2004-05-27 18:34:19.000000000 +0100
@@ -15,7 +15,7 @@
  *                           features support
  */
 
-/* $Id: uda1341.h,v 1.5 2003/04/19 13:34:32 perex Exp $ */
+/* $Id: uda1341.h,v 1.6 2004/05/03 17:36:50 tiwai Exp $ */
 
 #define UDA1341_ALSA_NAME "snd-uda1341"
 
--- diff/include/sound/version.h	2004-05-19 22:13:08.000000000 +0100
+++ source/include/sound/version.h	2004-05-27 18:34:19.000000000 +0100
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.4rc2"
-#define CONFIG_SND_DATE " (Tue Mar 30 08:19:30 2004 UTC)"
+#define CONFIG_SND_VERSION "1.0.4"
+#define CONFIG_SND_DATE " (Mon May 17 14:31:44 2004 UTC)"
--- diff/include/sound/ymfpci.h	2004-05-19 22:13:08.000000000 +0100
+++ source/include/sound/ymfpci.h	2004-05-27 18:34:19.000000000 +0100
@@ -393,11 +393,6 @@
 int snd_ymfpci_voice_alloc(ymfpci_t *chip, ymfpci_voice_type_t type, int pair, ymfpci_voice_t **rvoice);
 int snd_ymfpci_voice_free(ymfpci_t *chip, ymfpci_voice_t *pvoice);
 
-#ifdef CONFIG_PM
-void snd_ymfpci_suspend(ymfpci_t *chip);
-void snd_ymfpci_resume(ymfpci_t *chip);
-#endif
-
 #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 #define SUPPORT_JOYSTICK
 #endif
--- diff/init/initramfs.c	2004-05-19 22:13:08.000000000 +0100
+++ source/init/initramfs.c	2004-05-27 18:34:19.000000000 +0100
@@ -207,7 +207,7 @@
 
 static int __init do_skip(void)
 {
-	if (this_header + count <= next_header) {
+	if (this_header + count < next_header) {
 		eat(count);
 		return 1;
 	} else {
--- diff/init/main.c	2004-05-27 13:41:27.000000000 +0100
+++ source/init/main.c	2004-05-27 18:34:19.000000000 +0100
@@ -110,6 +110,9 @@
 void (*late_time_init)(void);
 extern void softirq_init(void);
 
+/* Untouched command line (eg. for /proc) saved by arch-specific code. */
+char saved_command_line[COMMAND_LINE_SIZE];
+
 static char *execute_command;
 
 /* Setup configured maximum number of CPUs to activate */
@@ -151,11 +154,18 @@
 {
 	struct obs_kernel_param *p;
 	extern struct obs_kernel_param __setup_start, __setup_end;
+	char *ptr;
+	int len = strlen(line);
 
+	if ((ptr = strchr(line, '=')))
+		len = ptr - line;
 	p = &__setup_start;
 	do {
 		int n = strlen(p->str);
-		if (!strncmp(line, p->str, n)) {
+		if (len <= n && !strncmp(line, p->str, n)) {
+			/* Already done in parse_early_param? */
+			if (p->early)
+				return 1;
 			if (!p->setup_func) {
 				printk(KERN_WARNING "Parameter %s is obsolete, ignored\n", p->str);
 				return 1;
@@ -389,6 +399,38 @@
  	cpu_idle();
 } 
 
+/* Check for early params. */
+static int __init do_early_param(char *param, char *val)
+{
+	struct obs_kernel_param *p;
+	extern struct obs_kernel_param __setup_start, __setup_end;
+
+	for (p = &__setup_start; p < &__setup_end; p++) {
+		if (p->early && strcmp(param, p->str) == 0) {
+			if (p->setup_func(val) != 0)
+				printk(KERN_WARNING
+				       "Malformed early option '%s'\n", param);
+		}
+	}
+	/* We accept everything at this stage. */
+	return 0;
+}
+
+/* Arch code calls this early on, or if not, just before other parsing. */
+void __init parse_early_param(void)
+{
+	static __initdata int done = 0;
+	static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];
+
+	if (done)
+		return;
+
+	/* All fall through to do_early_param. */
+	strlcpy(tmp_cmdline, saved_command_line, COMMAND_LINE_SIZE);
+	parse_args("early options", tmp_cmdline, NULL, 0, do_early_param);
+	done = 1;
+}
+
 /*
  *	Activate the first processor.
  */
@@ -396,7 +438,6 @@
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
-	extern char saved_command_line[];
 	extern struct kernel_param __start___param[], __stop___param[];
 /*
  * Interrupts are still disabled. Do necessary setups, then
@@ -423,12 +464,13 @@
 
 	build_all_zonelists();
 	page_alloc_init();
+	trap_init();
 	printk("Kernel command line: %s\n", saved_command_line);
+	parse_early_param();
 	parse_args("Booting kernel", command_line, __start___param,
 		   __stop___param - __start___param,
 		   &unknown_bootoption);
 	sort_main_extable();
-	trap_init();
 	rcu_init();
 	init_IRQ();
 	pidhash_init();
@@ -481,7 +523,6 @@
 	proc_root_init();
 #endif
 	check_bugs();
-	printk("POSIX conformance testing by UNIFIX\n");
 
 	/* 
 	 *	We count on the initial thread going ok 
@@ -670,3 +711,10 @@
 
 	panic("No init found.  Try passing init= option to kernel.");
 }
+
+static int early_param_test(char *rest)
+{
+	printk("early_parm_test: %s\n", rest ?: "(null)");
+	return rest ? 0 : -EINVAL;
+}
+early_param("testsetup", early_param_test);
--- diff/ipc/mqueue.c	2004-05-27 13:41:27.000000000 +0100
+++ source/ipc/mqueue.c	2004-05-27 18:34:19.000000000 +0100
@@ -43,10 +43,10 @@
 #define CTL_MSGSIZEMAX 	4
 
 /* default values */
-#define DFLT_QUEUESMAX	64	/* max number of message queues */
-#define DFLT_MSGMAX 	40	/* max number of messages in each queue */
+#define DFLT_QUEUESMAX	256	/* max number of message queues */
+#define DFLT_MSGMAX 	10	/* max number of messages in each queue */
 #define HARD_MSGMAX 	(131072/sizeof(void*))
-#define DFLT_MSGSIZEMAX 16384	/* max message size */
+#define DFLT_MSGSIZEMAX 8192	/* max message size */
 
 #define NOTIFY_COOKIE_LEN	32
 
@@ -67,6 +67,7 @@
 
 	struct sigevent notify;
 	pid_t notify_owner;
+ 	struct user_struct *user;	/* user who created, for accouting */
 	struct sock *notify_sock;
 	struct sk_buff *notify_cookie;
 
@@ -114,6 +115,9 @@
 
 		if (S_ISREG(mode)) {
 			struct mqueue_inode_info *info;
+			struct task_struct *p = current;
+			struct user_struct *u = p->user;
+			unsigned long mq_bytes, mq_msg_tblsz;
 
 			inode->i_fop = &mqueue_file_operations;
 			inode->i_size = FILENT_SIZE;
@@ -123,8 +127,10 @@
 			init_waitqueue_head(&info->wait_q);
 			INIT_LIST_HEAD(&info->e_wait_q[0].list);
 			INIT_LIST_HEAD(&info->e_wait_q[1].list);
+			info->messages = NULL;
 			info->notify_owner = 0;
 			info->qsize = 0;
+			info->user = NULL;	/* set when all is ok */
 			memset(&info->attr, 0, sizeof(info->attr));
 			info->attr.mq_maxmsg = DFLT_MSGMAX;
 			info->attr.mq_msgsize = DFLT_MSGSIZEMAX;
@@ -132,12 +138,29 @@
 				info->attr.mq_maxmsg = attr->mq_maxmsg;
 				info->attr.mq_msgsize = attr->mq_msgsize;
 			}
-			info->messages = kmalloc(info->attr.mq_maxmsg * sizeof(struct msg_msg *), GFP_KERNEL);
+			mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
+			mq_bytes = (mq_msg_tblsz +
+				(info->attr.mq_maxmsg * info->attr.mq_msgsize));
+
+			spin_lock(&mq_lock);
+			if (u->mq_bytes + mq_bytes < u->mq_bytes ||
+		 	    u->mq_bytes + mq_bytes >
+			    p->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
+				spin_unlock(&mq_lock);
+				goto out_inode;
+			}
+			u->mq_bytes += mq_bytes;
+			spin_unlock(&mq_lock);
+
+			info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
 			if (!info->messages) {
-				make_bad_inode(inode);
-				iput(inode);
-				inode = NULL;
+				spin_lock(&mq_lock);
+				u->mq_bytes -= mq_bytes;
+				spin_unlock(&mq_lock);
+				goto out_inode;
 			}
+			/* all is ok */
+			info->user = get_uid(u);
 		} else if (S_ISDIR(mode)) {
 			inode->i_nlink++;
 			/* Some things misbehave if size == 0 on a directory */
@@ -147,6 +170,10 @@
 		}
 	}
 	return inode;
+out_inode:
+	make_bad_inode(inode);
+	iput(inode);
+	return NULL;
 }
 
 static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
@@ -205,6 +232,8 @@
 static void mqueue_delete_inode(struct inode *inode)
 {
 	struct mqueue_inode_info *info;
+	struct user_struct *user;
+	unsigned long mq_bytes;
 	int i;
 
 	if (S_ISDIR(inode->i_mode)) {
@@ -220,10 +249,15 @@
 
 	clear_inode(inode);
 
-	if (info->messages) {
+	mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) +
+		   (info->attr.mq_maxmsg * info->attr.mq_msgsize));
+	user = info->user;
+	if (user) {
 		spin_lock(&mq_lock);
+		user->mq_bytes -= mq_bytes;
 		queues_count--;
 		spin_unlock(&mq_lock);
+		free_uid(user);
 	}
 }
 
@@ -534,6 +568,28 @@
 	info->notify_owner = 0;
 }
 
+static int mq_attr_ok(struct mq_attr *attr)
+{
+	if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
+		return 0;
+	if (capable(CAP_SYS_RESOURCE)) {
+		if (attr->mq_maxmsg > HARD_MSGMAX)
+			return 0;
+	} else {
+		if (attr->mq_maxmsg > msg_max ||
+				attr->mq_msgsize > msgsize_max)
+			return 0;
+	}
+	/* check for overflow */
+	if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
+		return 0;
+	if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) +
+	    (attr->mq_maxmsg * sizeof (struct msg_msg *)) <
+	    (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))
+		return 0;
+	return 1;
+}
+
 /*
  * Invoked when creating a new queue via sys_mq_open
  */
@@ -547,17 +603,8 @@
 	if (u_attr != NULL) {
 		if (copy_from_user(&attr, u_attr, sizeof(attr)))
 			return ERR_PTR(-EFAULT);
-
-		if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0)
+		if (!mq_attr_ok(&attr))
 			return ERR_PTR(-EINVAL);
-		if (capable(CAP_SYS_RESOURCE)) {
-			if (attr.mq_maxmsg > HARD_MSGMAX)
-				return ERR_PTR(-EINVAL);
-		} else {
-			if (attr.mq_maxmsg > msg_max ||
-					attr.mq_msgsize > msgsize_max)
-				return ERR_PTR(-EINVAL);
-		}
 		/* store for use during create */
 		dentry->d_fsdata = &attr;
 	}
--- diff/ipc/shm.c	2004-05-27 13:41:27.000000000 +0100
+++ source/ipc/shm.c	2004-05-27 18:34:19.000000000 +0100
@@ -796,10 +796,12 @@
 		 */
 		if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
 			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
-
+			int ret;
 
 			size = vma->vm_file->f_dentry->d_inode->i_size;
-			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
+			ret = do_munmap(mm, vma->vm_start,
+					vma->vm_end - vma->vm_start);
+			WARN_ON(ret);
 			/*
 			 * We discovered the size of the shm segment, so
 			 * break out of here and fall through to the next
@@ -823,9 +825,13 @@
 
 		/* finding a matching vma now does not alter retval */
 		if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
-			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
+			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
+			int ret;
 
-			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
+			ret = do_munmap(mm, vma->vm_start,
+					vma->vm_end - vma->vm_start);
+			WARN_ON(ret);
+		}
 		vma = next;
 	}
 
--- diff/kernel/Makefile	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/Makefile	2004-05-27 18:34:19.000000000 +0100
@@ -12,6 +12,7 @@
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
+obj-$(CONFIG_LOCKMETER) += lockmeter.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
--- diff/kernel/compat.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/compat.c	2004-05-27 18:34:19.000000000 +0100
@@ -208,7 +208,7 @@
 
 #ifdef CONFIG_FUTEX
 asmlinkage long compat_sys_futex(u32 *uaddr, int op, int val,
-		struct compat_timespec *utime, u32 *uaddr2)
+		struct compat_timespec *utime, u32 *uaddr2, int val3)
 {
 	struct timespec t;
 	unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
@@ -219,11 +219,11 @@
 			return -EFAULT;
 		timeout = timespec_to_jiffies(&t) + 1;
 	}
-	if (op == FUTEX_REQUEUE)
+	if (op >= FUTEX_REQUEUE)
 		val2 = (int) (long) utime;
 
 	return do_futex((unsigned long)uaddr, op, val, timeout,
-			(unsigned long)uaddr2, val2);
+			(unsigned long)uaddr2, val2, val3);
 }
 #endif
 
--- diff/kernel/fork.c	2004-05-27 13:41:27.000000000 +0100
+++ source/kernel/fork.c	2004-05-27 18:34:19.000000000 +0100
@@ -333,9 +333,9 @@
       
 			/* insert tmp into the share list, just after mpnt */
 			spin_lock(&file->f_mapping->i_mmap_lock);
-			flush_dcache_mmap_lock(mapping);
+			flush_dcache_mmap_lock(file->f_mapping);
 			vma_prio_tree_add(tmp, mpnt);
-			flush_dcache_mmap_unlock(mapping);
+			flush_dcache_mmap_unlock(file->f_mapping);
 			spin_unlock(&file->f_mapping->i_mmap_lock);
 		}
 
--- diff/kernel/futex.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/futex.c	2004-05-27 18:34:19.000000000 +0100
@@ -96,6 +96,7 @@
  */
 struct futex_hash_bucket {
        spinlock_t              lock;
+       unsigned int	    nqueued;
        struct list_head       chain;
 };
 
@@ -318,13 +319,14 @@
  * physical page.
  */
 static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
-				int nr_wake, int nr_requeue)
+			 int nr_wake, int nr_requeue, int *valp)
 {
 	union futex_key key1, key2;
 	struct futex_hash_bucket *bh1, *bh2;
 	struct list_head *head1;
 	struct futex_q *this, *next;
 	int ret, drop_count = 0;
+	unsigned int nqueued;
 
 	down_read(&current->mm->mmap_sem);
 
@@ -338,12 +340,41 @@
 	bh1 = hash_futex(&key1);
 	bh2 = hash_futex(&key2);
 
+	nqueued = bh1->nqueued;
+	if (likely(valp != NULL)) {
+		int curval;
+
+		/* In order to avoid doing get_user while
+		   holding bh1->lock and bh2->lock, nqueued
+		   (monotonically increasing field) must be first
+		   read, then *uaddr1 fetched from userland and
+		   after acquiring lock nqueued field compared with
+		   the stored value.  The smp_mb () below
+		   makes sure that bh1->nqueued is read from memory
+		   before *uaddr1.  */
+		smp_mb();
+
+		if (get_user(curval, (int *)uaddr1) != 0) {
+			ret = -EFAULT;
+			goto out;
+		}
+		if (curval != *valp) {
+			ret = -EAGAIN;
+			goto out;
+		}
+	}
+
 	if (bh1 < bh2)
 		spin_lock(&bh1->lock);
 	spin_lock(&bh2->lock);
 	if (bh1 > bh2)
 		spin_lock(&bh1->lock);
 
+	if (unlikely(nqueued != bh1->nqueued && valp != NULL)) {
+		ret = -EAGAIN;
+		goto out_unlock;
+	}
+
 	head1 = &bh1->chain;
 	list_for_each_entry_safe(this, next, head1, list) {
 		if (!match_futex (&this->key, &key1))
@@ -365,6 +396,7 @@
 		}
 	}
 
+out_unlock:
 	spin_unlock(&bh1->lock);
 	if (bh1 != bh2)
 		spin_unlock(&bh2->lock);
@@ -398,6 +430,7 @@
 	q->lock_ptr = &bh->lock;
 
 	spin_lock(&bh->lock);
+	bh->nqueued++;
 	list_add_tail(&q->list, &bh->chain);
 	spin_unlock(&bh->lock);
 }
@@ -625,7 +658,7 @@
 }
 
 long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
-		unsigned long uaddr2, int val2)
+		unsigned long uaddr2, int val2, int val3)
 {
 	int ret;
 
@@ -641,7 +674,10 @@
 		ret = futex_fd(uaddr, val);
 		break;
 	case FUTEX_REQUEUE:
-		ret = futex_requeue(uaddr, uaddr2, val, val2);
+		ret = futex_requeue(uaddr, uaddr2, val, val2, NULL);
+		break;
+	case FUTEX_CMP_REQUEUE:
+		ret = futex_requeue(uaddr, uaddr2, val, val2, &val3);
 		break;
 	default:
 		ret = -ENOSYS;
@@ -651,7 +687,8 @@
 
 
 asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
-			  struct timespec __user *utime, u32 __user *uaddr2)
+			  struct timespec __user *utime, u32 __user *uaddr2,
+			  int val3)
 {
 	struct timespec t;
 	unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
@@ -665,11 +702,11 @@
 	/*
 	 * requeue parameter in 'utime' if op == FUTEX_REQUEUE.
 	 */
-	if (op == FUTEX_REQUEUE)
+	if (op >= FUTEX_REQUEUE)
 		val2 = (int) (long) utime;
 
 	return do_futex((unsigned long)uaddr, op, val, timeout,
-			(unsigned long)uaddr2, val2);
+			(unsigned long)uaddr2, val2, val3);
 }
 
 static struct super_block *
--- diff/kernel/module.c	2004-05-27 13:41:27.000000000 +0100
+++ source/kernel/module.c	2004-05-27 18:34:19.000000000 +0100
@@ -36,7 +36,6 @@
 #include <linux/stop_machine.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
-#include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 
 #if 0
--- diff/kernel/pid.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/pid.c	2004-05-27 18:34:19.000000000 +0100
@@ -122,6 +122,8 @@
 	}
 	
 	if (!offset || !atomic_read(&map->nr_free)) {
+		if (!offset)
+			map--;
 next_map:
 		map = next_free_map(map, &max_steps);
 		if (!map)
@@ -268,6 +270,9 @@
  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
  * more.
  */
+#ifdef CONFIG_KGDB
+int kgdb_pid_init_done; /* so we don't call prior to... */
+#endif
 void __init pidhash_init(void)
 {
 	int i, j, pidhash_size;
@@ -289,6 +294,9 @@
 		for (j = 0; j < pidhash_size; j++)
 			INIT_LIST_HEAD(&pid_hash[i][j]);
 	}
+#ifdef CONFIG_KGDB
+	kgdb_pid_init_done++;
+#endif
 }
 
 void __init pidmap_init(void)
--- diff/kernel/posix-timers.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/posix-timers.c	2004-05-27 18:34:19.000000000 +0100
@@ -397,7 +397,6 @@
 	if (!tmr)
 		return tmr;
 	memset(tmr, 0, sizeof (struct k_itimer));
-	tmr->it_id = (timer_t)-1;
 	if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
 		kmem_cache_free(posix_timers_cache, tmr);
 		tmr = 0;
@@ -405,9 +404,11 @@
 	return tmr;
 }
 
-static void release_posix_timer(struct k_itimer *tmr)
+#define IT_ID_SET	1
+#define IT_ID_NOT_SET	0
+static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
 {
-	if (tmr->it_id != -1) {
+	if (it_id_set) {
 		unsigned long flags;
 		spin_lock_irqsave(&idr_lock, flags);
 		idr_remove(&posix_timers_id, tmr->it_id);
@@ -429,10 +430,11 @@
 {
 	int error = 0;
 	struct k_itimer *new_timer = NULL;
-	timer_t new_timer_id;
+	int new_timer_id;
 	struct task_struct *process = 0;
 	unsigned long flags;
 	sigevent_t event;
+	int it_id_set = IT_ID_NOT_SET;
 
 	if ((unsigned) which_clock >= MAX_CLOCKS ||
 				!posix_clocks[which_clock].res)
@@ -443,19 +445,38 @@
 		return -EAGAIN;
 
 	spin_lock_init(&new_timer->it_lock);
-	do {
-		if (unlikely(!idr_pre_get(&posix_timers_id, GFP_KERNEL))) {
-			error = -EAGAIN;
-			new_timer->it_id = (timer_t)-1;
-			goto out;
-		}
-		spin_lock_irq(&idr_lock);
-		new_timer_id = (timer_t) idr_get_new(&posix_timers_id,
-							(void *) new_timer);
-		spin_unlock_irq(&idr_lock);
-	} while (unlikely(new_timer_id == -1));
+ retry:
+	if (unlikely(!idr_pre_get(&posix_timers_id, GFP_KERNEL))) {
+		error = -EAGAIN;
+		goto out;
+	}
+	spin_lock_irq(&idr_lock);
+	error = idr_get_new(&posix_timers_id,
+			    (void *) new_timer,
+			    &new_timer_id);
+	spin_unlock_irq(&idr_lock);
+	if (error == -EAGAIN)
+		goto retry;
+	else if (error) {
+		/*
+		 * Wierd looking, but we return EAGAIN if the IDR is
+		 * full (proper POSIX return value for this)
+		 */
+		error = -EAGAIN;
+		goto out;
+	}
+
+	it_id_set = IT_ID_SET;
+	new_timer->it_id = (timer_t) new_timer_id;
+	new_timer->it_clock = which_clock;
+	new_timer->it_incr = 0;
+	new_timer->it_overrun = -1;
+	init_timer(&new_timer->it_timer);
+	new_timer->it_timer.expires = 0;
+	new_timer->it_timer.data = (unsigned long) new_timer;
+	new_timer->it_timer.function = posix_timer_fn;
+	set_timer_inactive(new_timer);
 
-	new_timer->it_id = new_timer_id;
 	/*
 	 * return the timer_id now.  The next step is hard to
 	 * back out if there is an error.
@@ -470,6 +491,10 @@
 			error = -EFAULT;
 			goto out;
 		}
+		new_timer->it_sigev_notify = event.sigev_notify;
+		new_timer->it_sigev_signo = event.sigev_signo;
+		new_timer->it_sigev_value = event.sigev_value;
+
 		read_lock(&tasklist_lock);
 		if ((process = good_sigevent(&event))) {
 			/*
@@ -489,6 +514,7 @@
 			 */
 			spin_lock_irqsave(&process->sighand->siglock, flags);
 			if (!(process->flags & PF_EXITING)) {
+				new_timer->it_process = process;
 				list_add(&new_timer->list,
 					 &process->signal->posix_timers);
 				spin_unlock_irqrestore(&process->sighand->siglock, flags);
@@ -503,35 +529,27 @@
 			error = -EINVAL;
 			goto out;
 		}
-		new_timer->it_sigev_notify = event.sigev_notify;
-		new_timer->it_sigev_signo = event.sigev_signo;
-		new_timer->it_sigev_value = event.sigev_value;
 	} else {
 		new_timer->it_sigev_notify = SIGEV_SIGNAL;
 		new_timer->it_sigev_signo = SIGALRM;
 		new_timer->it_sigev_value.sival_int = new_timer->it_id;
 		process = current->group_leader;
 		spin_lock_irqsave(&process->sighand->siglock, flags);
+		new_timer->it_process = process;
 		list_add(&new_timer->list, &process->signal->posix_timers);
 		spin_unlock_irqrestore(&process->sighand->siglock, flags);
 	}
 
-	new_timer->it_clock = which_clock;
-	new_timer->it_incr = 0;
-	new_timer->it_overrun = -1;
-	init_timer(&new_timer->it_timer);
-	new_timer->it_timer.expires = 0;
-	new_timer->it_timer.data = (unsigned long) new_timer;
-	new_timer->it_timer.function = posix_timer_fn;
-	set_timer_inactive(new_timer);
-
-	/*
-	 * Once we set the process, it can be found so do it last...
+ 	/*
+	 * In the case of the timer belonging to another task, after
+	 * the task is unlocked, the timer is owned by the other task
+	 * and may cease to exist at any time.  Don't use or modify
+	 * new_timer after the unlock call.
 	 */
-	new_timer->it_process = process;
+
 out:
 	if (error)
-		release_posix_timer(new_timer);
+		release_posix_timer(new_timer, it_id_set);
 
 	return error;
 }
@@ -952,7 +970,7 @@
 	timer->it_process = NULL;
 	}
 	unlock_timer(timer, flags);
-	release_posix_timer(timer);
+	release_posix_timer(timer, IT_ID_SET);
 	return 0;
 }
 /*
@@ -989,7 +1007,7 @@
 		timer->it_process = NULL;
 	}
 	unlock_timer(timer, flags);
-	release_posix_timer(timer);
+	release_posix_timer(timer, IT_ID_SET);
 }
 
 /*
--- diff/kernel/printk.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/printk.c	2004-05-27 18:34:19.000000000 +0100
@@ -472,6 +472,27 @@
 }
 
 /*
+ * Zap console related locks when oopsing. Only zap at most once
+ * every 10 seconds, to leave time for slow consoles to print a
+ * full oops.
+ */
+static void zap_locks(void)
+{
+	static unsigned long oops_timestamp;
+
+	if (time_after_eq(jiffies, oops_timestamp) &&
+			!time_after(jiffies, oops_timestamp + 30*HZ))
+		return;
+
+	oops_timestamp = jiffies;
+
+	/* If a crash is occurring, make sure we can't deadlock */
+	spin_lock_init(&logbuf_lock);
+	/* And make sure that we print immediately */
+	init_MUTEX(&console_sem);
+}
+
+/*
  * This is printk.  It can be called from any context.  We want it to work.
  * 
  * We try to grab the console_sem.  If we succeed, it's easy - we log the output and
@@ -493,12 +514,8 @@
 	static char printk_buf[1024];
 	static int log_level_unknown = 1;
 
-	if (oops_in_progress) {
-		/* If a crash is occurring, make sure we can't deadlock */
-		spin_lock_init(&logbuf_lock);
-		/* And make sure that we print immediately */
-		init_MUTEX(&console_sem);
-	}
+	if (unlikely(oops_in_progress))
+		zap_locks();
 
 	/* This stops the holder of console_sem just where we want him */
 	spin_lock_irqsave(&logbuf_lock, flags);
--- diff/kernel/rcupdate.c	2004-05-27 13:41:27.000000000 +0100
+++ source/kernel/rcupdate.c	2004-05-27 18:34:19.000000000 +0100
@@ -47,8 +47,17 @@
 
 /* Definition for rcupdate control block. */
 struct rcu_ctrlblk rcu_ctrlblk = 
-	{ .mutex = SPIN_LOCK_UNLOCKED, .curbatch = 1, 
-	  .maxbatch = 1, .rcu_cpu_mask = CPU_MASK_NONE };
+	{ .cur = -300, .completed = -300 , .lock = SEQCNT_ZERO };
+
+/* Bookkeeping of the progress of the grace period */
+struct {
+	spinlock_t	mutex; /* Guard this struct and writes to rcu_ctrlblk */
+	cpumask_t	rcu_cpu_mask; /* CPUs that need to switch in order    */
+	                              /* for current batch to proceed.        */
+} rcu_state ____cacheline_maxaligned_in_smp =
+	  {.mutex = SPIN_LOCK_UNLOCKED, .rcu_cpu_mask = CPU_MASK_NONE };
+
+
 DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L };
 
 /* Fake initialization required by compiler */
@@ -97,25 +106,61 @@
 }
 
 /*
+ * Grace period handling:
+ * The grace period handling consists out of two steps:
+ * - A new grace period is started.
+ *   This is done by rcu_start_batch. The start is not broadcasted to
+ *   all cpus, they must pick this up by comparing rcu_ctrlblk.cur with
+ *   RCU_quiescbatch(cpu). All cpus are recorded  in the
+ *   rcu_state.rcu_cpu_mask bitmap.
+ * - All cpus must go through a quiescent state.
+ *   Since the start of the grace period is not broadcasted, at least two
+ *   calls to rcu_check_quiescent_state are required:
+ *   The first call just notices that a new grace period is running. The
+ *   following calls check if there was a quiescent state since the beginning
+ *   of the grace period. If so, it updates rcu_state.rcu_cpu_mask. If
+ *   the bitmap is empty, then the grace period is completed.
+ *   rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace
+ *   period (if necessary).
+ */
+/*
  * Register a new batch of callbacks, and start it up if there is currently no
  * active batch and the batch to be registered has not already occurred.
- * Caller must hold the rcu_ctrlblk lock.
+ * Caller must hold rcu_state.mutex.
  */
-static void rcu_start_batch(long newbatch)
+static void rcu_start_batch(int next_pending)
 {
 	cpumask_t active;
 
-	if (rcu_batch_before(rcu_ctrlblk.maxbatch, newbatch)) {
-		rcu_ctrlblk.maxbatch = newbatch;
+	if (next_pending)
+		rcu_ctrlblk.next_pending = 1;
+
+	if (rcu_ctrlblk.next_pending &&
+			rcu_ctrlblk.completed == rcu_ctrlblk.cur) {
+		/* Can't change, since spin lock held. */
+		active = nohz_cpu_mask;
+		cpus_complement(active);
+		cpus_and(rcu_state.rcu_cpu_mask, cpu_online_map, active);
+		write_seqcount_begin(&rcu_ctrlblk.lock);
+		rcu_ctrlblk.next_pending = 0;
+		rcu_ctrlblk.cur++;
+		write_seqcount_end(&rcu_ctrlblk.lock);
 	}
-	if (rcu_batch_before(rcu_ctrlblk.maxbatch, rcu_ctrlblk.curbatch) ||
-	    !cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
-		return;
+}
+
+/*
+ * cpu went through a quiescent state since the beginning of the grace period.
+ * Clear it from the cpu mask and complete the grace period if it was the last
+ * cpu. Start another grace period if someone has further entries pending
+ */
+static void cpu_quiet(int cpu)
+{
+	cpu_clear(cpu, rcu_state.rcu_cpu_mask);
+	if (cpus_empty(rcu_state.rcu_cpu_mask)) {
+		/* batch completed ! */
+		rcu_ctrlblk.completed = rcu_ctrlblk.cur;
+		rcu_start_batch(0);
 	}
-	/* Can't change, since spin lock held. */
-	active = nohz_cpu_mask;
-	cpus_complement(active);
-	cpus_and(rcu_ctrlblk.rcu_cpu_mask, cpu_online_map, active);
 }
 
 /*
@@ -127,7 +172,19 @@
 {
 	int cpu = smp_processor_id();
 
-	if (!cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask))
+	if (RCU_quiescbatch(cpu) != rcu_ctrlblk.cur) {
+		/* new grace period: record qsctr value. */
+		RCU_qs_pending(cpu) = 1;
+		RCU_last_qsctr(cpu) = RCU_qsctr(cpu);
+		RCU_quiescbatch(cpu) = rcu_ctrlblk.cur;
+		return;
+	}
+
+	/* Grace period already completed for this cpu?
+	 * qs_pending is checked instead of the actual bitmap to avoid
+	 * cacheline trashing.
+	 */
+	if (!RCU_qs_pending(cpu))
 		return;
 
 	/* 
@@ -135,27 +192,19 @@
 	 * we may miss one quiescent state of that CPU. That is
 	 * tolerable. So no need to disable interrupts.
 	 */
-	if (RCU_last_qsctr(cpu) == RCU_QSCTR_INVALID) {
-		RCU_last_qsctr(cpu) = RCU_qsctr(cpu);
-		return;
-	}
 	if (RCU_qsctr(cpu) == RCU_last_qsctr(cpu))
 		return;
+	RCU_qs_pending(cpu) = 0;
 
-	spin_lock(&rcu_ctrlblk.mutex);
-	if (!cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask))
-		goto out_unlock;
-
-	cpu_clear(cpu, rcu_ctrlblk.rcu_cpu_mask);
-	RCU_last_qsctr(cpu) = RCU_QSCTR_INVALID;
-	if (!cpus_empty(rcu_ctrlblk.rcu_cpu_mask))
-		goto out_unlock;
-
-	rcu_ctrlblk.curbatch++;
-	rcu_start_batch(rcu_ctrlblk.maxbatch);
+	spin_lock(&rcu_state.mutex);
+	/*
+	 * RCU_quiescbatch/batch.cur and the cpu bitmap can come out of sync
+	 * during cpu startup. Ignore the quiescent state.
+	 */
+	if (likely(RCU_quiescbatch(cpu) == rcu_ctrlblk.cur))
+		cpu_quiet(cpu);
 
-out_unlock:
-	spin_unlock(&rcu_ctrlblk.mutex);
+	spin_unlock(&rcu_state.mutex);
 }
 
 
@@ -185,25 +234,11 @@
 	 * we can block indefinitely waiting for it, so flush
 	 * it here
 	 */
-	spin_lock_irq(&rcu_ctrlblk.mutex);
-	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask))
-		goto unlock;
-
-	cpu_clear(cpu, rcu_ctrlblk.rcu_cpu_mask);
-	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
-		rcu_ctrlblk.curbatch++;
-		/* We may avoid calling start batch if
-		 * we are starting the batch only
-		 * because of the DEAD CPU (the current
-		 * CPU will start a new batch anyway for
-		 * the callbacks we will move to current CPU).
-		 * However, we will avoid this optimisation
-		 * for now.
-		 */
-		rcu_start_batch(rcu_ctrlblk.maxbatch);
-	}
+	spin_lock_bh(&rcu_state.mutex);
+	if (rcu_ctrlblk.cur != rcu_ctrlblk.completed)
+		cpu_quiet(cpu);
 unlock:
-	spin_unlock_irq(&rcu_ctrlblk.mutex);
+	spin_unlock_bh(&rcu_state.mutex);
 
 	rcu_move_batch(&RCU_curlist(cpu));
 	rcu_move_batch(&RCU_nxtlist(cpu));
@@ -213,6 +248,14 @@
 
 #endif
 
+void rcu_restart_cpu(int cpu)
+{
+	spin_lock_bh(&rcu_state.mutex);
+	RCU_quiescbatch(cpu) = rcu_ctrlblk.completed;
+	RCU_qs_pending(cpu) = 0;
+	spin_unlock_bh(&rcu_state.mutex);
+}
+
 /*
  * This does the RCU processing work from tasklet context. 
  */
@@ -222,13 +265,15 @@
 	LIST_HEAD(list);
 
 	if (!list_empty(&RCU_curlist(cpu)) &&
-	    rcu_batch_after(rcu_ctrlblk.curbatch, RCU_batch(cpu))) {
+			!rcu_batch_before(rcu_ctrlblk.completed,RCU_batch(cpu))) {
 		__list_splice(&RCU_curlist(cpu), &list);
 		INIT_LIST_HEAD(&RCU_curlist(cpu));
 	}
 
 	local_irq_disable();
 	if (!list_empty(&RCU_nxtlist(cpu)) && list_empty(&RCU_curlist(cpu))) {
+		int next_pending, seq;
+
 		__list_splice(&RCU_nxtlist(cpu), &RCU_curlist(cpu));
 		INIT_LIST_HEAD(&RCU_nxtlist(cpu));
 		local_irq_enable();
@@ -236,10 +281,19 @@
 		/*
 		 * start the next batch of callbacks
 		 */
-		spin_lock(&rcu_ctrlblk.mutex);
-		RCU_batch(cpu) = rcu_ctrlblk.curbatch + 1;
-		rcu_start_batch(RCU_batch(cpu));
-		spin_unlock(&rcu_ctrlblk.mutex);
+		do {
+			seq = read_seqcount_begin(&rcu_ctrlblk.lock);
+			/* determine batch number */
+			RCU_batch(cpu) = rcu_ctrlblk.cur + 1;
+			next_pending = rcu_ctrlblk.next_pending;
+		} while (read_seqcount_retry(&rcu_ctrlblk.lock, seq));
+
+		if (!next_pending) {
+			/* and start it/schedule start if it's a new batch */
+			spin_lock(&rcu_state.mutex);
+			rcu_start_batch(1);
+			spin_unlock(&rcu_state.mutex);
+		}
 	} else {
 		local_irq_enable();
 	}
@@ -263,6 +317,8 @@
 	tasklet_init(&RCU_tasklet(cpu), rcu_process_callbacks, 0UL);
 	INIT_LIST_HEAD(&RCU_nxtlist(cpu));
 	INIT_LIST_HEAD(&RCU_curlist(cpu));
+	RCU_quiescbatch(cpu) = rcu_ctrlblk.completed;
+	RCU_qs_pending(cpu) = 0;
 }
 
 static int __devinit rcu_cpu_notify(struct notifier_block *self, 
--- diff/kernel/sched.c	2004-05-27 13:41:27.000000000 +0100
+++ source/kernel/sched.c	2004-05-27 18:34:19.000000000 +0100
@@ -26,6 +26,7 @@
 #include <linux/highmem.h>
 #include <linux/smp_lock.h>
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
 #include <linux/interrupt.h>
 #include <linux/completion.h>
 #include <linux/kernel_stat.h>
@@ -40,6 +41,8 @@
 #include <linux/cpu.h>
 #include <linux/percpu.h>
 #include <linux/kthread.h>
+#include <linux/seq_file.h>
+#include <linux/times.h>
 
 #include <asm/unistd.h>
 
@@ -141,8 +144,7 @@
 	(v1) * (v2_max) / (v1_max)
 
 #define DELTA(p) \
-	(SCALE(TASK_NICE(p), 40, MAX_USER_PRIO*PRIO_BONUS_RATIO/100) + \
-		INTERACTIVE_DELTA)
+	(SCALE(TASK_NICE(p), 40, MAX_BONUS) + INTERACTIVE_DELTA)
 
 #define TASK_INTERACTIVE(p) \
 	((p)->prio <= (p)->static_prio - DELTA(p))
@@ -218,6 +220,7 @@
 	unsigned long expired_timestamp, nr_uninterruptible;
 	unsigned long long timestamp_last_tick;
 	task_t *curr, *idle;
+
 	struct mm_struct *prev_mm;
 	prio_array_t *active, *expired, arrays[2];
 	int best_expired_prio;
@@ -233,6 +236,22 @@
 	task_t *migration_thread;
 	struct list_head migration_queue;
 #endif
+#ifdef CONFIG_SCHEDSTATS
+	/* sys_sched_yield stats */
+	unsigned long yld_exp_empty;
+	unsigned long yld_act_empty;
+	unsigned long yld_both_empty;
+	unsigned long yld_cnt;
+
+	/* schedule stats */
+	unsigned long sched_cnt;
+	unsigned long sched_switch;
+	unsigned long sched_idle;
+
+	/* wake stats */
+	unsigned long sched_wake;
+	unsigned long sched_wake_local;
+#endif
 };
 
 static DEFINE_PER_CPU(struct runqueue, runqueues);
@@ -279,6 +298,91 @@
 	spin_unlock_irqrestore(&rq->lock, *flags);
 }
 
+
+#ifdef CONFIG_SCHEDSTATS
+
+/*
+ * bump this up when changing the output format or the meaning of an existing
+ * format, so that tools can adapt (or abort)
+ */
+#define SCHEDSTAT_VERSION	7
+
+static int show_schedstat(struct seq_file *seq, void *v)
+{
+	int i;
+
+	seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION);
+	seq_printf(seq, "timestamp %lu\n", jiffies);
+	for_each_cpu(i) {
+		/* Include offline CPUs */
+		runqueue_t *rq = cpu_rq(i);
+#ifdef CONFIG_SMP
+		struct sched_domain *sd;
+		int j = 0;
+#endif
+
+		seq_printf(seq,
+		    "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+		    i,
+		    rq->yld_both_empty, rq->yld_act_empty,
+		    rq->yld_exp_empty, rq->yld_cnt,
+		    rq->sched_switch, rq->sched_cnt,
+		    rq->sched_idle, rq->sched_wake, rq->sched_wake_local);
+#ifdef CONFIG_SMP
+		for_each_domain(i, sd) {
+			char str[NR_CPUS];
+			int k;
+			cpumask_scnprintf(str, NR_CPUS, sd->span);
+			seq_printf(seq, " domain%d %s", j++, str);
+
+			for (k = 0; k < 3; k++) {
+				seq_printf(seq, " %lu %lu %lu %lu %lu %lu",
+				    sd->lb_cnt[k], sd->lb_balanced[k],
+				    sd->lb_failed[k], sd->lb_pulled[k],
+				    sd->lb_hot_pulled[k], sd->lb_imbalance[k]);
+			}
+
+			seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu",
+			    sd->alb_cnt, sd->alb_failed,
+			    sd->alb_pushed, sd->sched_wake_remote,
+			    sd->plb_pulled, sd->afw_pulled,
+			    sd->sbe_pushed, sd->sbc_pushed);
+		}
+#endif
+
+		seq_printf(seq, "\n");
+	}
+
+	return 0;
+}
+
+static int schedstat_open(struct inode *inode, struct file *file)
+{
+	unsigned size = 4096 * (1 + num_online_cpus() / 32);
+	char *buf = kmalloc(size, GFP_KERNEL);
+	struct seq_file *m;
+	int res;
+
+	if (!buf)
+		return -ENOMEM;
+	res = single_open(file, show_schedstat, NULL);
+	if (!res) {
+		m = file->private_data;
+		m->buf = buf;
+		m->size = size;
+	} else
+		kfree(buf);
+	return res;
+}
+
+struct file_operations proc_schedstat_operations = {
+	.open    = schedstat_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release,
+};
+#endif
+
 /*
  * rq_lock - lock a given runqueue and disable interrupts.
  */
@@ -751,7 +855,24 @@
 	cpu = task_cpu(p);
 	this_cpu = smp_processor_id();
 
+	schedstat_inc(rq, sched_wake);
+#ifndef CONFIG_SMP
+	schedstat_inc(rq, sched_wake_local);
+#endif
+
 #ifdef CONFIG_SMP
+#ifdef CONFIG_SCHEDSTATS
+	if (cpu == this_cpu)
+		schedstat_inc(rq, sched_wake_local);
+	else {
+		for_each_domain(this_cpu, sd)
+			if (cpu_isset(cpu, sd->span))
+				break;
+		if (sd)
+			schedstat_inc(sd, sched_wake_remote);
+	}
+#endif
+
 	if (unlikely(task_running(rq, p)))
 		goto out_activate;
 
@@ -785,12 +906,22 @@
 				!task_hot(p, rq->timestamp_last_tick, sd))
 			|| ((sd->flags & SD_WAKE_BALANCE) &&
 				imbalance*this_load <= 100*load) ) {
+
 			/*
 			 * Now sd has SD_WAKE_AFFINE and p is cache cold in sd
 			 * or sd has SD_WAKE_BALANCE and there is an imbalance
 			 */
-			if (cpu_isset(cpu, sd->span))
+			if (cpu_isset(cpu, sd->span)) {
+#ifdef CONFIG_SCHEDSTATS
+				if ((sd->flags & SD_WAKE_AFFINE) &&
+					!task_hot(p, rq->timestamp_last_tick, sd))
+					schedstat_inc(sd, afw_pulled);
+				else if ((sd->flags & SD_WAKE_BALANCE) &&
+					imbalance*this_load <= 100*load)
+					schedstat_inc(sd, plb_pulled);
+#endif
 				goto out_set_cpu;
+			}
 		}
 	}
 
@@ -1274,6 +1405,7 @@
 			rq->nr_running++;
 		}
 	} else {
+		schedstat_inc(sd, sbc_pushed);
 		/* Not the local CPU - must adjust timestamp */
 		p->timestamp = (p->timestamp - this_rq->timestamp_last_tick)
 					+ rq->timestamp_last_tick;
@@ -1313,6 +1445,7 @@
 		wake_up_process(mt);
 		put_task_struct(mt);
 		wait_for_completion(&req.done);
+		tlb_migrate_finish(p->mm);
 		return;
 	}
 out:
@@ -1342,6 +1475,7 @@
 	if (sd) {
 		new_cpu = find_idlest_cpu(current, this_cpu, sd);
 		if (new_cpu != this_cpu) {
+  			schedstat_inc(sd, sbe_pushed);
 			put_cpu();
 			sched_migrate_task(current, new_cpu);
 			return;
@@ -1414,6 +1548,13 @@
 			return 0;
 	}
 
+#ifdef CONFIG_SCHEDSTATS
+	if (!task_hot(p, rq->timestamp_last_tick, sd))
+		schedstat_inc(sd, lb_pulled[idle]);
+	else
+		schedstat_inc(sd, lb_hot_pulled[idle]);
+#endif
+
 	return 1;
 }
 
@@ -1677,18 +1818,25 @@
 	int nr_moved;
 
 	spin_lock(&this_rq->lock);
+	schedstat_inc(sd, lb_cnt[idle]);
 
 	group = find_busiest_group(sd, this_cpu, &imbalance, idle);
-	if (!group)
+	if (!group) {
+		schedstat_inc(sd, lb_balanced[idle]);
 		goto out_balanced;
+	}
 
 	busiest = find_busiest_queue(group);
-	if (!busiest)
+	if (!busiest) {
+		schedstat_inc(sd, lb_balanced[idle]);
 		goto out_balanced;
+	}
+
 	if (unlikely(busiest == this_rq)) {
 		WARN_ON(1);
 		goto out_balanced;
 	}
+	schedstat_add(sd, lb_imbalance[idle], imbalance);
 
 	nr_moved = 0;
 	if (busiest->nr_running > 1) {
@@ -1706,6 +1854,7 @@
 	spin_unlock(&this_rq->lock);
 
 	if (!nr_moved) {
+		schedstat_inc(sd, lb_failed[idle]);
 		sd->nr_balance_failed++;
 
 		if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {
@@ -1760,13 +1909,20 @@
 	unsigned long imbalance;
 	int nr_moved = 0;
 
+ 	schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
 	group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE);
-	if (!group)
+	if (!group) {
+		schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
 		goto out;
+	}
 
 	busiest = find_busiest_queue(group);
-	if (!busiest || busiest == this_rq)
+	if (!busiest || busiest == this_rq) {
+		schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
 		goto out;
+	}
+
+	schedstat_add(sd, lb_imbalance[NEWLY_IDLE], imbalance);
 
 	/* Attempt to move tasks */
 	double_lock_balance(this_rq, busiest);
@@ -1811,6 +1967,7 @@
 	struct sched_domain *sd;
 	struct sched_group *group, *busy_group;
 	int i;
+	int moved = 0;
 
 	if (busiest->nr_running <= 1)
 		return;
@@ -1822,6 +1979,7 @@
 		WARN_ON(1);
 		return;
 	}
+	schedstat_inc(sd, alb_cnt);
 
  	group = sd->groups;
 	while (!cpu_isset(busiest_cpu, group->cpumask))
@@ -1849,11 +2007,16 @@
 
 		rq = cpu_rq(push_cpu);
 		double_lock_balance(busiest, rq);
-		move_tasks(rq, push_cpu, busiest, 1, sd, IDLE);
+		moved += move_tasks(rq, push_cpu, busiest, 1, sd, IDLE);
 		spin_unlock(&rq->lock);
 next_group:
 		group = group->next;
 	} while (group != sd->groups);
+
+	if (moved)
+		schedstat_add(sd, alb_pushed, moved);
+	else
+		schedstat_inc(sd, alb_failed);
 }
 
 /*
@@ -2193,6 +2356,7 @@
 	rq = this_rq();
 
 	release_kernel_lock(prev);
+ 	schedstat_inc(rq, sched_cnt);
 	now = sched_clock();
 	if (likely(now - prev->timestamp < NS_MAX_SLEEP_AVG))
 		run_time = now - prev->timestamp;
@@ -2230,6 +2394,7 @@
 			next = rq->idle;
 			rq->expired_timestamp = 0;
 			wake_sleeping_dependent(cpu, rq);
+ 			schedstat_inc(rq, sched_idle);
 			goto switch_tasks;
 		}
 	}
@@ -2239,6 +2404,7 @@
 		/*
 		 * Switch the active and expired arrays.
 		 */
+		schedstat_inc(rq, sched_switch);
 		rq->active = rq->expired;
 		rq->expired = array;
 		array = rq->active;
@@ -2589,6 +2755,13 @@
 
 EXPORT_SYMBOL(set_user_nice);
 
+#ifdef CONFIG_KGDB
+struct task_struct *kgdb_get_idle(int this_cpu)
+{
+        return cpu_rq(this_cpu)->idle;
+}
+#endif
+
 #ifdef __ARCH_WANT_SYS_NICE
 
 /*
@@ -2976,6 +3149,7 @@
 	prio_array_t *array = current->array;
 	prio_array_t *target = rq->expired;
 
+	schedstat_inc(rq, yld_cnt);
 	/*
 	 * We implement yielding by moving the task into the expired
 	 * queue.
@@ -2991,10 +3165,9 @@
 
 	/*
 	 * Since we are going to call schedule() anyway, there's
-	 * no need to preempt:
+	 * no need to preempt or enable interrupts:
 	 */
 	_raw_spin_unlock(&rq->lock);
-	local_irq_enable();
 	preempt_enable_no_resched();
 
 	schedule();
@@ -3319,6 +3492,7 @@
 		task_rq_unlock(rq, &flags);
 		wake_up_process(rq->migration_thread);
 		wait_for_completion(&req.done);
+		tlb_migrate_finish(p->mm);
 		return 0;
 	}
 out:
@@ -3568,7 +3742,8 @@
 		/* Idle task back to normal (off runqueue, low prio) */
 		rq = task_rq_lock(rq->idle, &flags);
 		deactivate_task(rq->idle, rq);
-		__setscheduler(rq->idle, SCHED_NORMAL, MAX_PRIO);
+		rq->idle->static_prio = MAX_PRIO;
+		__setscheduler(rq->idle, SCHED_NORMAL, 0);
 		task_rq_unlock(rq, &flags);
  		BUG_ON(rq->nr_running != 0);
 
--- diff/kernel/signal.c	2004-05-27 13:41:27.000000000 +0100
+++ source/kernel/signal.c	2004-05-27 18:34:19.000000000 +0100
@@ -32,9 +32,6 @@
 
 static kmem_cache_t *sigqueue_cachep;
 
-atomic_t nr_queued_signals;
-int max_queued_signals = 1024;
-
 /*
  * In POSIX a signal is sent either to a specific thread (Linux task)
  * or to the process as a whole (Linux thread group).  How the signal
@@ -265,17 +262,19 @@
 	return sig;
 }
 
-struct sigqueue *__sigqueue_alloc(void)
+static struct sigqueue *__sigqueue_alloc(void)
 {
 	struct sigqueue *q = 0;
 
-	if (atomic_read(&nr_queued_signals) < max_queued_signals)
+	if (atomic_read(&current->user->sigpending) <
+			current->rlim[RLIMIT_SIGPENDING].rlim_cur)
 		q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC);
 	if (q) {
-		atomic_inc(&nr_queued_signals);
 		INIT_LIST_HEAD(&q->list);
 		q->flags = 0;
 		q->lock = 0;
+		q->user = get_uid(current->user);
+		atomic_inc(&q->user->sigpending);
 	}
 	return(q);
 }
@@ -284,8 +283,9 @@
 {
 	if (q->flags & SIGQUEUE_PREALLOC)
 		return;
+	atomic_dec(&q->user->sigpending);
+	free_uid(q->user);
 	kmem_cache_free(sigqueue_cachep, q);
-	atomic_dec(&nr_queued_signals);
 }
 
 static void flush_sigqueue(struct sigpending *queue)
@@ -699,7 +699,8 @@
 	}
 }
 
-static int send_signal(int sig, struct siginfo *info, struct sigpending *signals)
+static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
+			struct sigpending *signals)
 {
 	struct sigqueue * q = NULL;
 	int ret = 0;
@@ -719,12 +720,14 @@
 	   make sure at least one signal gets delivered and don't
 	   pass on the info struct.  */
 
-	if (atomic_read(&nr_queued_signals) < max_queued_signals)
+	if (atomic_read(&t->user->sigpending) <
+			t->rlim[RLIMIT_SIGPENDING].rlim_cur)
 		q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC);
 
 	if (q) {
-		atomic_inc(&nr_queued_signals);
 		q->flags = 0;
+		q->user = get_uid(t->user);
+		atomic_inc(&q->user->sigpending);
 		list_add_tail(&q->list, &signals->list);
 		switch ((unsigned long) info) {
 		case 0:
@@ -798,7 +801,7 @@
 	if (LEGACY_QUEUE(&t->pending, sig))
 		goto out;
 
-	ret = send_signal(sig, info, &t->pending);
+	ret = send_signal(sig, info, t, &t->pending);
 	if (!ret && !sigismember(&t->blocked, sig))
 		signal_wake_up(t, sig == SIGKILL);
 out:
@@ -999,7 +1002,7 @@
 	 * We always use the shared queue for process-wide signals,
 	 * to avoid several races.
 	 */
-	ret = send_signal(sig, info, &p->signal->shared_pending);
+	ret = send_signal(sig, info, p, &p->signal->shared_pending);
 	if (unlikely(ret))
 		return ret;
 
--- diff/kernel/softirq.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/softirq.c	2004-05-27 18:34:19.000000000 +0100
@@ -132,11 +132,22 @@
 
 void local_bh_enable(void)
 {
+	if (in_irq()) {
+		printk("local_bh_enable() was called in hard irq context.   "
+			"This is probably a bug\n");
+		dump_stack();
+	}
+
 	__local_bh_enable();
-	WARN_ON(irqs_disabled());
-	if (unlikely(!in_interrupt() &&
-		     local_softirq_pending()))
+	if (unlikely(!in_interrupt() && local_softirq_pending())) {
+		if (irqs_disabled()) {
+			printk("local_bh_enable() was called with local "
+				"interrupts disabled.  This is probably a"
+				" bug\n");
+			dump_stack();
+		}
 		invoke_softirq();
+	}
 	preempt_check_resched();
 }
 EXPORT_SYMBOL(local_bh_enable);
@@ -300,8 +311,7 @@
 
 void tasklet_kill(struct tasklet_struct *t)
 {
-	if (in_interrupt())
-		printk("Attempt to kill tasklet from interrupt\n");
+	might_sleep();
 
 	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
 		do
--- diff/kernel/sys.c	2004-05-27 13:41:27.000000000 +0100
+++ source/kernel/sys.c	2004-05-27 18:34:19.000000000 +0100
@@ -1281,8 +1281,12 @@
 
 	groups_sort(group_info);
 	get_group_info(group_info);
+
+	task_lock(current);
 	old_info = current->group_info;
 	current->group_info = group_info;
+	task_unlock(current);
+
 	put_group_info(old_info);
 
 	return 0;
@@ -1302,6 +1306,7 @@
 	if (gidsetsize < 0)
 		return -EINVAL;
 
+	/* no need to grab task_lock here; it cannot change */
 	get_group_info(current->group_info);
 	i = current->group_info->ngroups;
 	if (gidsetsize) {
--- diff/kernel/sysctl.c	2004-05-27 13:41:27.000000000 +0100
+++ source/kernel/sysctl.c	2004-05-27 18:34:19.000000000 +0100
@@ -53,8 +53,6 @@
 extern int sysctl_overcommit_memory;
 extern int sysctl_overcommit_ratio;
 extern int max_threads;
-extern atomic_t nr_queued_signals;
-extern int max_queued_signals;
 extern int sysrq_enabled;
 extern int core_uses_pid;
 extern char core_pattern[];
@@ -429,22 +427,6 @@
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
-	{
-		.ctl_name	= KERN_RTSIGNR,
-		.procname	= "rtsig-nr",
-		.data		= &nr_queued_signals,
-		.maxlen		= sizeof(int),
-		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.ctl_name	= KERN_RTSIGMAX,
-		.procname	= "rtsig-max",
-		.data		= &max_queued_signals,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
 #ifdef CONFIG_SYSVIPC
 	{
 		.ctl_name	= KERN_SHMMAX,
--- diff/kernel/uid16.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/uid16.c	2004-05-27 18:34:19.000000000 +0100
@@ -39,7 +39,7 @@
 
 asmlinkage long sys_setgid16(old_gid_t gid)
 {
-	return sys_setgid((gid_t)gid);
+	return sys_setgid(low2highgid(gid));
 }
 
 asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid)
@@ -49,7 +49,7 @@
 
 asmlinkage long sys_setuid16(old_uid_t uid)
 {
-	return sys_setuid((uid_t)uid);
+	return sys_setuid(low2highuid(uid));
 }
 
 asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
@@ -88,12 +88,12 @@
 
 asmlinkage long sys_setfsuid16(old_uid_t uid)
 {
-	return sys_setfsuid((uid_t)uid);
+	return sys_setfsuid(low2highuid(uid));
 }
 
 asmlinkage long sys_setfsgid16(old_gid_t gid)
 {
-	return sys_setfsgid((gid_t)gid);
+	return sys_setfsgid(low2highgid(gid));
 }
 
 static int groups16_to_user(old_gid_t __user *grouplist,
@@ -103,7 +103,7 @@
 	old_gid_t group;
 
 	for (i = 0; i < group_info->ngroups; i++) {
-		group = (old_gid_t)GROUP_AT(group_info, i);
+		group = high2lowgid(GROUP_AT(group_info, i));
 		if (put_user(group, grouplist+i))
 			return -EFAULT;
 	}
@@ -120,7 +120,7 @@
 	for (i = 0; i < group_info->ngroups; i++) {
 		if (get_user(group, grouplist+i))
 			return  -EFAULT;
-		GROUP_AT(group_info, i) = (gid_t)group;
+		GROUP_AT(group_info, i) = low2highgid(group);
 	}
 
 	return 0;
--- diff/kernel/user.c	2004-05-27 13:41:27.000000000 +0100
+++ source/kernel/user.c	2004-05-27 18:34:19.000000000 +0100
@@ -30,7 +30,9 @@
 struct user_struct root_user = {
 	.__count	= ATOMIC_INIT(1),
 	.processes	= ATOMIC_INIT(1),
-	.files		= ATOMIC_INIT(0)
+	.files		= ATOMIC_INIT(0),
+	.sigpending	= ATOMIC_INIT(0),
+	.mq_bytes	= 0
 };
 
 /*
@@ -108,6 +110,9 @@
 		atomic_set(&new->__count, 1);
 		atomic_set(&new->processes, 0);
 		atomic_set(&new->files, 0);
+		atomic_set(&new->sigpending, 0);
+
+		new->mq_bytes = 0;
 
 		/*
 		 * Before adding this, check whether we raced
--- diff/lib/Kconfig	2004-05-19 22:13:10.000000000 +0100
+++ source/lib/Kconfig	2004-05-27 18:34:19.000000000 +0100
@@ -21,6 +21,9 @@
 	  require M here.  See Castagnoli93.
 	  Module will be libcrc32c.
 
+config QSORT
+	bool "Quick Sort"
+
 #
 # compression support is select'ed if needed
 #
--- diff/lib/Makefile	2004-05-19 22:13:10.000000000 +0100
+++ source/lib/Makefile	2004-05-27 18:34:19.000000000 +0100
@@ -20,6 +20,7 @@
 
 obj-$(CONFIG_CRC32)	+= crc32.o
 obj-$(CONFIG_LIBCRC32C)	+= libcrc32c.o
+obj-$(CONFIG_QSORT)	+= qsort.o
 
 obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
 obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
--- diff/lib/idr.c	2004-05-19 22:13:10.000000000 +0100
+++ source/lib/idr.c	2004-05-27 18:34:19.000000000 +0100
@@ -27,15 +27,6 @@
  * so you don't need to be too concerned about locking and conflicts
  * with the slab allocator.
 
- * A word on reuse.  We reuse empty id slots as soon as we can, always
- * using the lowest one available.  But we also merge a counter in the
- * high bits of the id.  The counter is RESERVED_ID_BITS (8 at this time)
- * long.  This means that if you allocate and release the same id in a 
- * loop we will reuse an id after about 256 times around the loop.  The
- * word about is used here as we will NOT return a valid id of -1 so if
- * you loop on the largest possible id (and that is 24 bits, wow!) we
- * will kick the counter to avoid -1.  (Paranoid?  You bet!)
- *
  * What you need to do is, since we don't keep the counter as part of
  * id / ptr pair, to keep a copy of it in the pointed to structure
  * (or else where) so that when you ask for a ptr you can varify that
@@ -70,14 +61,21 @@
  *   sleep, so must not be called with any spinlocks held.  If the system is
  *   REALLY out of memory this function returns 0, other wise 1.
 
- * int idr_get_new(struct idr *idp, void *ptr);
+ * int idr_get_new(struct idr *idp, void *ptr, int *id);
  
  *   This is the allocate id function.  It should be called with any
  *   required locks.  In fact, in the SMP case, you MUST lock prior to
- *   calling this function to avoid possible out of memory problems.  If
- *   memory is required, it will return a -1, in which case you should
- *   unlock and go back to the idr_pre_get() call.  ptr is the pointer
- *   you want associated with the id.  In other words:
+ *   calling this function to avoid possible out of memory problems.
+ *   If memory is required, it will return -EAGAIN, you should unlock
+ *   and go back to the idr_pre_get() call.  If the idr is full, it
+ *   will return a -ENOSPC.  ptr is the pointer you want associated
+ *   with the id.  The value is returned in the "id" field.  idr_get_new()
+ *   returns a value in the range 0 ... 0x7fffffff
+
+ * int idr_get_new_above(struct idr *idp, void *ptr, int start_id, int *id);
+
+ *   Like idr_get_new(), but the returned id is guaranteed to be at or
+ *   above start_id.
 
  * void *idr_find(struct idr *idp, int id);
  
@@ -92,6 +90,10 @@
  *   removes the given id, freeing that slot and any memory that may
  *   now be unused.  See idr_find() for locking restrictions.
 
+ * int idr_full(struct idr *idp);
+
+ *   Returns true if the idr is full and false if not.
+
  */
 
 
@@ -115,7 +117,7 @@
 
 	spin_lock(&idp->lock);
 	if (!(p = idp->id_free))
-		BUG();
+		return NULL;
 	idp->id_free = p->ary[0];
 	idp->id_free_cnt--;
 	p->ary[0] = 0;
@@ -181,8 +183,8 @@
 			sh = IDR_BITS*l;
 			id = ((id >> sh) ^ n ^ m) << sh;
 		}
-		if (id >= MAX_ID_BIT)
-			return -1;
+		if ((id >= MAX_ID_BIT) || (id < 0))
+			return -3;
 		if (l == 0)
 			break;
 		/*
@@ -220,7 +222,7 @@
 	return(id);
 }
 
-int idr_get_new_above(struct idr *idp, void *ptr, int starting_id)
+static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
 {
 	struct idr_layer *p, *new;
 	int layers, v, id;
@@ -238,7 +240,7 @@
 	 * Add a new layer to the top of the tree if the requested
 	 * id is larger than the currently allocated space.
 	 */
-	while (id >= (1 << (layers*IDR_BITS))) {
+	while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
 		layers++;
 		if (!p->count)
 			continue;
@@ -266,23 +268,47 @@
 	v = sub_alloc(idp, ptr, &id);
 	if (v == -2)
 		goto build_up;
-	if ( likely(v >= 0 )) {
-		idp->count++;
-		v += (idp->count << MAX_ID_SHIFT);
-		if ( unlikely( v == -1 ))
-		     v += (1L << MAX_ID_SHIFT);
-	}
 	return(v);
 }
+
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
+{
+	int rv;
+	rv = idr_get_new_above_int(idp, ptr, starting_id);
+	/*
+	 * This is a cheap hack until the IDR code can be fixed to
+	 * return proper error values.
+	 */
+	if (rv < 0) {
+		if (rv == -1)
+			return -EAGAIN;
+		else /* Will be -3 */
+			return -ENOSPC;
+	}
+	*id = rv;
+	return 0;
+}
 EXPORT_SYMBOL(idr_get_new_above);
 
-int idr_get_new(struct idr *idp, void *ptr)
+int idr_get_new(struct idr *idp, void *ptr, int *id)
 {
-	return idr_get_new_above(idp, ptr, 0);
+	int rv;
+	rv = idr_get_new_above_int(idp, ptr, 0);
+	/*
+	 * This is a cheap hack until the IDR code can be fixed to
+	 * return proper error values.
+	 */
+	if (rv < 0) {
+		if (rv == -1)
+			return -EAGAIN;
+		else /* Will be -3 */
+			return -ENOSPC;
+	}
+	*id = rv;
+	return 0;
 }
 EXPORT_SYMBOL(idr_get_new);
 
-
 static void sub_remove(struct idr *idp, int shift, int id)
 {
 	struct idr_layer *p = idp->top;
@@ -311,10 +337,14 @@
 			idp->layers = 0;
 	}
 }
+
 void idr_remove(struct idr *idp, int id)
 {
 	struct idr_layer *p;
 
+	/* Mask off upper bits we don't use for the search. */
+	id &= MAX_ID_MASK;
+
 	sub_remove(idp, (idp->layers - 1) * IDR_BITS, id);
 	if ( idp->top && idp->top->count == 1 && 
 	     (idp->layers > 1) &&
@@ -350,6 +380,9 @@
 	if ( unlikely( (id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS)))
 	     return NULL;
 #endif
+	/* Mask off upper bits we don't use for the search. */
+	id &= MAX_ID_MASK;
+
 	while (n > 0 && p) {
 		n -= IDR_BITS;
 		p = p->ary[(id >> n) & IDR_MASK];
--- diff/lib/radix-tree.c	2004-05-27 13:41:27.000000000 +0100
+++ source/lib/radix-tree.c	2004-05-27 18:34:19.000000000 +0100
@@ -136,13 +136,12 @@
 
 static inline void tag_set(struct radix_tree_node *node, int tag, int offset)
 {
-	if (!test_bit(offset, &node->tags[tag][0]))
-		__set_bit(offset, &node->tags[tag][0]);
+	set_bit(offset, &node->tags[tag][0]);
 }
 
 static inline void tag_clear(struct radix_tree_node *node, int tag, int offset)
 {
-	__clear_bit(offset, &node->tags[tag][0]);
+	clear_bit(offset, &node->tags[tag][0]);
 }
 
 static inline int tag_get(struct radix_tree_node *node, int tag, int offset)
@@ -321,6 +320,11 @@
  *
  *	Returns the address of the tagged item.   Setting a tag on a not-present
  *	item is a bug.
+ *
+ *	radix_tree_tag_set() atomically sets the tag and does not actually
+ *	change the overall tree structure.  Consequently it is sufficient that
+ *	the caller use an rwlock in read-mode while running
+ *	radix_tree_tag_set().
  */
 void *radix_tree_tag_set(struct radix_tree_root *root,
 			unsigned long index, int tag)
@@ -362,6 +366,11 @@
  *
  *	Returns the address of the tagged item on success, else NULL.  ie:
  *	has the same return value and semantics as radix_tree_lookup().
+ *
+ *	radix_tree_tag_clear() atomically sets the tag and does not actually
+ *	change the overall tree structure.  Consequently it is sufficient that
+ *	the caller use an rwlock in read-mode while running
+ *	radix_tree_tag_clear().
  */
 void *radix_tree_tag_clear(struct radix_tree_root *root,
 			unsigned long index, int tag)
--- diff/mm/filemap.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/filemap.c	2004-05-27 18:34:19.000000000 +0100
@@ -114,9 +114,9 @@
 	if (unlikely(!PageLocked(page)))
 		PAGE_BUG(page);
 
-	spin_lock_irq(&mapping->tree_lock);
+	write_lock_irq(&mapping->tree_lock);
 	__remove_from_page_cache(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	write_unlock_irq(&mapping->tree_lock);
 }
 
 static inline int sync_page(struct page *page)
@@ -253,7 +253,7 @@
 	int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
 
 	if (error == 0) {
-		spin_lock_irq(&mapping->tree_lock);
+		write_lock_irq(&mapping->tree_lock);
 		error = radix_tree_insert(&mapping->page_tree, offset, page);
 		if (!error) {
 			page_cache_get(page);
@@ -263,7 +263,7 @@
 			mapping->nrpages++;
 			pagecache_acct(1);
 		}
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		radix_tree_preload_end();
 	}
 	return error;
@@ -436,11 +436,11 @@
 	 * We scan the hash list read-only. Addition to and removal from
 	 * the hash-list needs a held write-lock.
 	 */
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page)
 		page_cache_get(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -453,11 +453,11 @@
 {
 	struct page *page;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page && TestSetPageLocked(page))
 		page = NULL;
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -479,15 +479,15 @@
 {
 	struct page *page;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 repeat:
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page) {
 		page_cache_get(page);
 		if (TestSetPageLocked(page)) {
-			spin_unlock_irq(&mapping->tree_lock);
+			read_unlock_irq(&mapping->tree_lock);
 			lock_page(page);
-			spin_lock_irq(&mapping->tree_lock);
+			read_lock_irq(&mapping->tree_lock);
 
 			/* Has the page been truncated while we slept? */
 			if (page->mapping != mapping || page->index != offset) {
@@ -497,7 +497,7 @@
 			}
 		}
 	}
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -571,12 +571,12 @@
 	unsigned int i;
 	unsigned int ret;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	ret = radix_tree_gang_lookup(&mapping->page_tree,
 				(void **)pages, start, nr_pages);
 	for (i = 0; i < ret; i++)
 		page_cache_get(pages[i]);
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
 
@@ -590,14 +590,14 @@
 	unsigned int i;
 	unsigned int ret;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	ret = radix_tree_gang_lookup_tag(&mapping->page_tree,
 				(void **)pages, *index, nr_pages, tag);
 	for (i = 0; i < ret; i++)
 		page_cache_get(pages[i]);
 	if (ret)
 		*index = pages[ret - 1]->index + 1;
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
 
@@ -650,7 +650,8 @@
 			     read_actor_t actor)
 {
 	struct inode *inode = mapping->host;
-	unsigned long index, offset;
+	unsigned long index, end_index, offset;
+	loff_t isize;
 	struct page *cached_page;
 	int error;
 	struct file_ra_state ra = *_ra;
@@ -659,26 +660,18 @@
 	index = *ppos >> PAGE_CACHE_SHIFT;
 	offset = *ppos & ~PAGE_CACHE_MASK;
 
+	isize = i_size_read(inode);
+	end_index = isize >> PAGE_CACHE_SHIFT;
+	if (index > end_index)
+		goto out;
+
 	for (;;) {
 		struct page *page;
-		unsigned long end_index, nr, ret;
-		loff_t isize = i_size_read(inode);
-
-		end_index = isize >> PAGE_CACHE_SHIFT;
-			
-		if (index > end_index)
-			break;
-		nr = PAGE_CACHE_SIZE;
-		if (index == end_index) {
-			nr = isize & ~PAGE_CACHE_MASK;
-			if (nr <= offset)
-				break;
-		}
+		unsigned long nr, ret;
 
 		cond_resched();
 		page_cache_readahead(mapping, &ra, filp, index);
 
-		nr = nr - offset;
 find_page:
 		page = find_get_page(mapping, index);
 		if (unlikely(page == NULL)) {
@@ -688,6 +681,17 @@
 		if (!PageUptodate(page))
 			goto page_not_up_to_date;
 page_ok:
+		/* nr is the maximum number of bytes to copy from this page */
+		nr = PAGE_CACHE_SIZE;
+		if (index == end_index) {
+			nr = isize & ~PAGE_CACHE_MASK;
+			if (nr <= offset) {
+				page_cache_release(page);
+				goto out;
+			}
+		}
+		nr = nr - offset;
+
 		/* If users can be writing to this page using arbitrary
 		 * virtual addresses, take care about potential aliasing
 		 * before reading the page on the kernel side.
@@ -719,7 +723,7 @@
 		page_cache_release(page);
 		if (ret == nr && desc->count)
 			continue;
-		break;
+		goto out;
 
 page_not_up_to_date:
 		/* Get exclusive access to the page ... */
@@ -739,22 +743,41 @@
 		}
 
 readpage:
-		/* ... and start the actual read. The read will unlock the page. */
+		/* Start the actual read. The read will unlock the page. */
 		error = mapping->a_ops->readpage(filp, page);
 
-		if (!error) {
-			if (PageUptodate(page))
-				goto page_ok;
+		if (unlikely(error))
+			goto readpage_error;
+
+		if (!PageUptodate(page)) {
 			wait_on_page_locked(page);
-			if (PageUptodate(page))
-				goto page_ok;
-			error = -EIO;
+			if (!PageUptodate(page)) {
+				error = -EIO;
+				goto readpage_error;
+			}
+		}
+
+		/*
+		 * i_size must be checked after we have done ->readpage.
+		 *
+		 * Checking i_size after the readpage allows us to calculate
+		 * the correct value for "nr", which means the zero-filled
+		 * part of the page is not copied back to userspace (unless
+		 * another truncate extends the file - this is desired though).
+		 */
+		isize = i_size_read(inode);
+		end_index = isize >> PAGE_CACHE_SHIFT;
+		if (index > end_index) {
+			page_cache_release(page);
+			goto out;
 		}
+		goto page_ok;
 
+readpage_error:
 		/* UHHUH! A synchronous read error occurred. Report it */
 		desc->error = error;
 		page_cache_release(page);
-		break;
+		goto out;
 
 no_cached_page:
 		/*
@@ -765,7 +788,7 @@
 			cached_page = page_cache_alloc_cold(mapping);
 			if (!cached_page) {
 				desc->error = -ENOMEM;
-				break;
+				goto out;
 			}
 		}
 		error = add_to_page_cache_lru(cached_page, mapping,
@@ -774,13 +797,14 @@
 			if (error == -EEXIST)
 				goto find_page;
 			desc->error = error;
-			break;
+			goto out;
 		}
 		page = cached_page;
 		cached_page = NULL;
 		goto readpage;
 	}
 
+out:
 	*_ra = ra;
 
 	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
--- diff/mm/highmem.c	2004-05-19 22:13:11.000000000 +0100
+++ source/mm/highmem.c	2004-05-27 18:34:19.000000000 +0100
@@ -26,7 +26,6 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;
--- diff/mm/memory.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/memory.c	2004-05-27 18:34:19.000000000 +0100
@@ -700,6 +700,7 @@
 		struct page **pages, struct vm_area_struct **vmas)
 {
 	int i;
+	int vm_io;
 	unsigned int flags;
 
 	/* 
@@ -743,9 +744,11 @@
 			continue;
 		}
 
-		if (!vma || (pages && (vma->vm_flags & VM_IO))
-				|| !(flags & vma->vm_flags))
-			return i ? : -EFAULT;
+		if (!vma)
+			return i ? i : -EFAULT;
+		vm_io = vma->vm_flags & VM_IO;
+		if ((pages && vm_io) || !(flags & vma->vm_flags))
+			return i ? i : -EFAULT;
 
 		if (is_vm_hugetlb_page(vma)) {
 			i = follow_hugetlb_page(mm, vma, pages, vmas,
@@ -754,8 +757,15 @@
 		}
 		spin_lock(&mm->page_table_lock);
 		do {
-			struct page *map;
+			struct page *map = NULL;
 			int lookup_write = write;
+
+			/*
+			 * We don't follow pagetables for VM_IO regions - they
+			 * may have no pageframes.
+			 */
+			if (vm_io)
+				goto no_follow;
 			while (!(map = follow_page(mm, start, lookup_write))) {
 				/*
 				 * Shortcut for anonymous pages. We don't want
@@ -807,6 +817,7 @@
 				if (!PageReserved(pages[i]))
 					page_cache_get(pages[i]);
 			}
+no_follow:
 			if (vmas)
 				vmas[i] = vma;
 			i++;
@@ -1004,7 +1015,7 @@
 	flush_cache_page(vma, address);
 	entry = maybe_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)),
 			      vma);
-	ptep_establish(vma, address, page_table, entry);
+	ptep_establish(vma, address, page_table, entry, 1);
 	update_mmu_cache(vma, address, entry);
 }
 
@@ -1056,7 +1067,7 @@
 			flush_cache_page(vma, address);
 			entry = maybe_mkwrite(pte_mkyoung(pte_mkdirty(pte)),
 					      vma);
-			ptep_establish(vma, address, page_table, entry);
+			ptep_establish(vma, address, page_table, entry, 1);
 			update_mmu_cache(vma, address, entry);
 			pte_unmap(page_table);
 			spin_unlock(&mm->page_table_lock);
@@ -1210,6 +1221,8 @@
 {
 	struct address_space *mapping = inode->i_mapping;
 	unsigned long limit;
+	loff_t i_size;
+	struct page *page;
 
 	if (inode->i_size < offset)
 		goto do_expand;
@@ -1224,8 +1237,24 @@
 		goto out_sig;
 	if (offset > inode->i_sb->s_maxbytes)
 		goto out;
-	i_size_write(inode, offset);
 
+	/*
+	 * Put a pagecache page at the current i_size and lock it while
+	 * modifying i_size to synchronise against block_write_full_page()'s
+	 * sampling of i_size.  Otherwise block_write_full_page() may decide to
+	 * memset part of this page after the application extended the file
+	 * size.
+	 */
+	i_size = inode->i_size;	/* don't need i_size_read() due to i_sem */
+	page = NULL;
+	if (i_size & (PAGE_CACHE_SIZE - 1))
+		page = grab_cache_page(inode->i_mapping,
+					i_size >> PAGE_CACHE_SHIFT);
+	i_size_write(inode, offset);
+	if (page) {
+		unlock_page(page);
+		page_cache_release(page);
+	}
 out_truncate:
 	if (inode->i_op && inode->i_op->truncate)
 		inode->i_op->truncate(inode);
@@ -1646,7 +1675,7 @@
 		entry = pte_mkdirty(entry);
 	}
 	entry = pte_mkyoung(entry);
-	ptep_establish(vma, address, pte, entry);
+	ptep_establish(vma, address, pte, entry, write_access);
 	update_mmu_cache(vma, address, entry);
 	pte_unmap(pte);
 	spin_unlock(&mm->page_table_lock);
--- diff/mm/mempolicy.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/mempolicy.c	2004-05-27 18:34:19.000000000 +0100
@@ -444,17 +444,16 @@
 
 /* Copy a kernel node mask to user space */
 static int copy_nodes_to_user(unsigned long *user_mask, unsigned long maxnode,
-			      unsigned long *nodes)
+			      void *nodes, unsigned nbytes)
 {
 	unsigned long copy = ALIGN(maxnode-1, 64) / 8;
 
-	if (copy > sizeof(nodes)) {
+	if (copy > nbytes) {
 		if (copy > PAGE_SIZE)
 			return -EINVAL;
-		if (clear_user((char*)user_mask + sizeof(nodes),
-				copy - sizeof(nodes)))
+		if (clear_user((char*)user_mask + nbytes, copy - nbytes))
 			return -EFAULT;
-		copy = sizeof(nodes);
+		copy = nbytes;
 	}
 	return copy_to_user(user_mask, nodes, copy) ? -EFAULT : 0;
 }
@@ -514,7 +513,7 @@
 	if (nmask) {
 		DECLARE_BITMAP(nodes, MAX_NUMNODES);
 		get_zonemask(pol, nodes);
-		err = copy_nodes_to_user(nmask, maxnode, nodes);
+		err = copy_nodes_to_user(nmask, maxnode, nodes, sizeof(nodes));
 	}
 
  out:
--- diff/mm/mincore.c	2004-05-19 22:13:11.000000000 +0100
+++ source/mm/mincore.c	2004-05-27 18:34:19.000000000 +0100
@@ -14,7 +14,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 
 /*
  * Later we can get more picky about what "in core" means precisely.
--- diff/mm/mmap.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/mmap.c	2004-05-27 18:34:19.000000000 +0100
@@ -25,7 +25,6 @@
 #include <linux/rmap.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 #include <asm/tlb.h>
 
@@ -951,7 +950,7 @@
 	}
 	if (flags & MAP_POPULATE) {
 		up_write(&mm->mmap_sem);
-		sys_remap_file_pages(addr, len, prot,
+		sys_remap_file_pages(addr, len, 0,
 					pgoff, flags & MAP_NONBLOCK);
 		down_write(&mm->mmap_sem);
 	}
--- diff/mm/mprotect.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/mprotect.c	2004-05-27 18:34:19.000000000 +0100
@@ -19,7 +19,6 @@
 #include <linux/mempolicy.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
--- diff/mm/mremap.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/mremap.c	2004-05-27 18:34:19.000000000 +0100
@@ -18,7 +18,6 @@
 #include <linux/security.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
--- diff/mm/msync.c	2004-05-19 22:13:11.000000000 +0100
+++ source/mm/msync.c	2004-05-27 18:34:19.000000000 +0100
@@ -13,7 +13,6 @@
 #include <linux/mman.h>
 
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 /*
--- diff/mm/nommu.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/nommu.c	2004-05-27 18:34:19.000000000 +0100
@@ -20,7 +20,6 @@
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 
-#include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
--- diff/mm/page-writeback.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/page-writeback.c	2004-05-27 18:34:19.000000000 +0100
@@ -566,7 +566,7 @@
 		struct address_space *mapping = page_mapping(page);
 
 		if (mapping) {
-			spin_lock_irq(&mapping->tree_lock);
+			read_lock_irq(&mapping->tree_lock);
 			mapping = page_mapping(page);
 			if (page_mapping(page)) { /* Race with truncate? */
 				BUG_ON(page_mapping(page) != mapping);
@@ -575,7 +575,7 @@
 				radix_tree_tag_set(&mapping->page_tree,
 					page_index(page), PAGECACHE_TAG_DIRTY);
 			}
-			spin_unlock_irq(&mapping->tree_lock);
+			read_unlock_irq(&mapping->tree_lock);
 			if (mapping->host) {
 				/* !PageAnon && !swapper_space */
 				__mark_inode_dirty(mapping->host,
@@ -650,17 +650,17 @@
 	unsigned long flags;
 
 	if (mapping) {
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		read_lock_irqsave(&mapping->tree_lock, flags);
 		if (TestClearPageDirty(page)) {
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
-			spin_unlock_irqrestore(&mapping->tree_lock, flags);
+			read_unlock_irqrestore(&mapping->tree_lock, flags);
 			if (!mapping->backing_dev_info->memory_backed)
 				dec_page_state(nr_dirty);
 			return 1;
 		}
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		read_unlock_irqrestore(&mapping->tree_lock, flags);
 		return 0;
 	}
 	return TestClearPageDirty(page);
@@ -707,15 +707,15 @@
 	if (mapping) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		read_lock_irqsave(&mapping->tree_lock, flags);
 		if (TestClearPageDirty(page)) {
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
-			spin_unlock_irqrestore(&mapping->tree_lock, flags);
+			read_unlock_irqrestore(&mapping->tree_lock, flags);
 			return 1;
 		}
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		read_unlock_irqrestore(&mapping->tree_lock, flags);
 		return 0;
 	}
 	return TestClearPageDirty(page);
@@ -729,13 +729,13 @@
 	if (mapping) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		read_lock_irqsave(&mapping->tree_lock, flags);
 		ret = TestClearPageWriteback(page);
 		if (ret)
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_WRITEBACK);
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		read_unlock_irqrestore(&mapping->tree_lock, flags);
 	} else {
 		ret = TestClearPageWriteback(page);
 	}
@@ -750,7 +750,7 @@
 	if (mapping) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		read_lock_irqsave(&mapping->tree_lock, flags);
 		ret = TestSetPageWriteback(page);
 		if (!ret)
 			radix_tree_tag_set(&mapping->page_tree,
@@ -760,7 +760,7 @@
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		read_unlock_irqrestore(&mapping->tree_lock, flags);
 	} else {
 		ret = TestSetPageWriteback(page);
 	}
@@ -778,9 +778,9 @@
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&mapping->tree_lock, flags);
+	read_lock_irqsave(&mapping->tree_lock, flags);
 	ret = radix_tree_tagged(&mapping->page_tree, tag);
-	spin_unlock_irqrestore(&mapping->tree_lock, flags);
+	read_unlock_irqrestore(&mapping->tree_lock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(mapping_tagged);
--- diff/mm/pdflush.c	2004-05-19 22:13:12.000000000 +0100
+++ source/mm/pdflush.c	2004-05-27 18:34:19.000000000 +0100
@@ -88,6 +88,8 @@
 	unsigned long when_i_went_to_sleep;
 };
 
+static int wakeup_count = 100;
+
 static int __pdflush(struct pdflush_work *my_work)
 {
 	current->flags |= PF_FLUSHER;
@@ -114,7 +116,10 @@
 
 		spin_lock_irq(&pdflush_lock);
 		if (!list_empty(&my_work->list)) {
-			printk("pdflush: bogus wakeup!\n");
+			if (wakeup_count > 0) {
+				wakeup_count--;
+				printk("pdflush: bogus wakeup!\n");
+			}
 			my_work->fn = NULL;
 			continue;
 		}
@@ -190,6 +195,7 @@
 {
 	unsigned long flags;
 	int ret = 0;
+	static int poke_count = 0;
 
 	if (fn == NULL)
 		BUG();		/* Hard to diagnose if it's deferred */
@@ -198,9 +204,19 @@
 	if (list_empty(&pdflush_list)) {
 		spin_unlock_irqrestore(&pdflush_lock, flags);
 		ret = -1;
+		if (wakeup_count < 100 && poke_count < 10) {
+			printk("%s: no threads\n", __FUNCTION__);
+			dump_stack();
+			poke_count++;
+		}
 	} else {
 		struct pdflush_work *pdf;
 
+		if (wakeup_count < 100 && poke_count < 10) {
+			printk("%s: found a thread\n", __FUNCTION__);
+			dump_stack();
+			poke_count++;
+		}
 		pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
 		list_del_init(&pdf->list);
 		if (list_empty(&pdflush_list))
--- diff/mm/prio_tree.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/prio_tree.c	2004-05-27 18:34:19.000000000 +0100
@@ -661,4 +661,3 @@
 	} else
 		return NULL;
 }
-EXPORT_SYMBOL(vma_prio_tree_next);
--- diff/mm/readahead.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/readahead.c	2004-05-27 18:34:19.000000000 +0100
@@ -234,7 +234,7 @@
 	/*
 	 * Preallocate as many pages as we will need.
 	 */
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
 		unsigned long page_offset = offset + page_idx;
 		
@@ -245,16 +245,16 @@
 		if (page)
 			continue;
 
-		spin_unlock_irq(&mapping->tree_lock);
+		read_unlock_irq(&mapping->tree_lock);
 		page = page_cache_alloc_cold(mapping);
-		spin_lock_irq(&mapping->tree_lock);
+		read_lock_irq(&mapping->tree_lock);
 		if (!page)
 			break;
 		page->index = page_offset;
 		list_add(&page->lru, &page_pool);
 		ret++;
 	}
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 
 	/*
 	 * Now start the IO.  We ignore I/O errors - if the page is not
--- diff/mm/rmap.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/rmap.c	2004-05-27 18:34:19.000000000 +0100
@@ -537,11 +537,7 @@
  * there there won't be many ptes located within the scan cluster.  In this case
  * maybe we could scan further - to the end of the pte page, perhaps.
  */
-#define CLUSTER_SIZE	(32 * PAGE_SIZE)
-#if     CLUSTER_SIZE  >	PMD_SIZE
-#undef  CLUSTER_SIZE
-#define CLUSTER_SIZE	PMD_SIZE
-#endif
+#define CLUSTER_SIZE	min(32*PAGE_SIZE, PMD_SIZE)
 #define CLUSTER_MASK	(~(CLUSTER_SIZE - 1))
 
 static int try_to_unmap_cluster(unsigned long cursor,
--- diff/mm/shmem.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/shmem.c	2004-05-27 18:34:19.000000000 +0100
@@ -1676,51 +1676,45 @@
 	return 0;
 }
 
-static int shmem_readlink_inline(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	return vfs_readlink(dentry, buffer, buflen, (const char *)SHMEM_I(dentry->d_inode));
-}
-
 static int shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
 {
-	return vfs_follow_link(nd, (const char *)SHMEM_I(dentry->d_inode));
+	nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
+	return 0;
 }
 
-static int shmem_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct page *page = NULL;
 	int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
-	if (res)
-		return res;
-	res = vfs_readlink(dentry, buffer, buflen, kmap(page));
-	kunmap(page);
-	mark_page_accessed(page);
-	page_cache_release(page);
-	return res;
+	nd_set_link(nd, res ? ERR_PTR(res) : kmap(page));
+	return 0;
 }
 
-static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void shmem_put_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct page *page = NULL;
-	int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
-	if (res)
-		return res;
-	res = vfs_follow_link(nd, kmap(page));
-	kunmap(page);
-	mark_page_accessed(page);
-	page_cache_release(page);
-	return res;
+	if (!IS_ERR(nd_get_link(nd))) {
+		struct page *page;
+
+		page = find_get_page(dentry->d_inode->i_mapping, 0);
+		if (!page)
+			BUG();
+		kunmap(page);
+		mark_page_accessed(page);
+		page_cache_release(page);
+		page_cache_release(page);
+	}
 }
 
 static struct inode_operations shmem_symlink_inline_operations = {
-	.readlink	= shmem_readlink_inline,
+	.readlink	= generic_readlink,
 	.follow_link	= shmem_follow_link_inline,
 };
 
 static struct inode_operations shmem_symlink_inode_operations = {
 	.truncate	= shmem_truncate,
-	.readlink	= shmem_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= shmem_follow_link,
+	.put_link	= shmem_put_link,
 };
 
 static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes)
--- diff/mm/slab.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/slab.c	2004-05-27 18:34:19.000000000 +0100
@@ -2032,6 +2032,15 @@
 		*dbg_redzone1(cachep, objp) = RED_ACTIVE;
 		*dbg_redzone2(cachep, objp) = RED_ACTIVE;
 	}
+	{
+		int objnr;
+		struct slab *slabp;
+
+		slabp = GET_PAGE_SLAB(virt_to_page(objp));
+
+		objnr = (objp - slabp->s_mem) / cachep->objsize;
+		slab_bufctl(slabp)[objnr] = (unsigned long)caller;
+	}
 	objp += obj_dbghead(cachep);
 	if (cachep->ctor && cachep->flags & SLAB_POISON) {
 		unsigned long	ctor_flags = SLAB_CTOR_CONSTRUCTOR;
@@ -2093,12 +2102,14 @@
 		objnr = (objp - slabp->s_mem) / cachep->objsize;
 		check_slabp(cachep, slabp);
 #if DEBUG
+#if 0
 		if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) {
 			printk(KERN_ERR "slab: double free detected in cache '%s', objp %p.\n",
 						cachep->name, objp);
 			BUG();
 		}
 #endif
+#endif
 		slab_bufctl(slabp)[objnr] = slabp->free;
 		slabp->free = objnr;
 		STATS_DEC_ACTIVE(cachep);
@@ -2948,6 +2959,29 @@
 	.show	= s_show,
 };
 
+static void do_dump_slabp(kmem_cache_t *cachep)
+{
+#if DEBUG
+	struct list_head *q;
+
+	check_irq_on();
+	spin_lock_irq(&cachep->spinlock);
+	list_for_each(q,&cachep->lists.slabs_full) {
+		struct slab *slabp;
+		int i;
+		slabp = list_entry(q, struct slab, list);
+		for (i = 0; i < cachep->num; i++) {
+			unsigned long sym = slab_bufctl(slabp)[i];
+
+			printk("obj %p/%d: %p", slabp, i, (void *)sym);
+			print_symbol(" <%s>", sym);
+			printk("\n");
+		}
+	}
+	spin_unlock_irq(&cachep->spinlock);
+#endif
+}
+
 #define MAX_SLABINFO_WRITE 128
 /**
  * slabinfo_write - Tuning for the slab allocator
@@ -2988,9 +3022,11 @@
 			    batchcount < 1 ||
 			    batchcount > limit ||
 			    shared < 0) {
-				res = -EINVAL;
+				do_dump_slabp(cachep);
+				res = 0;
 			} else {
-				res = do_tune_cpucache(cachep, limit, batchcount, shared);
+				res = do_tune_cpucache(cachep, limit,
+							batchcount, shared);
 			}
 			break;
 		}
--- diff/mm/swap_state.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/swap_state.c	2004-05-27 18:34:19.000000000 +0100
@@ -34,7 +34,7 @@
 
 struct address_space swapper_space = {
 	.page_tree	= RADIX_TREE_INIT(GFP_ATOMIC),
-	.tree_lock	= SPIN_LOCK_UNLOCKED,
+	.tree_lock	= RW_LOCK_UNLOCKED,
 	.a_ops		= &swap_aops,
 	.backing_dev_info = &swap_backing_dev_info,
 };
@@ -71,7 +71,7 @@
 	BUG_ON(PagePrivate(page));
 	error = radix_tree_preload(gfp_mask);
 	if (!error) {
-		spin_lock_irq(&swapper_space.tree_lock);
+		write_lock_irq(&swapper_space.tree_lock);
 		error = radix_tree_insert(&swapper_space.page_tree,
 						entry.val, page);
 		if (!error) {
@@ -82,7 +82,7 @@
 			total_swapcache_pages++;
 			pagecache_acct(1);
 		}
-		spin_unlock_irq(&swapper_space.tree_lock);
+		write_unlock_irq(&swapper_space.tree_lock);
 		radix_tree_preload_end();
 	}
 	return error;
@@ -209,9 +209,9 @@
   
 	entry.val = page->private;
 
-	spin_lock_irq(&swapper_space.tree_lock);
+	write_lock_irq(&swapper_space.tree_lock);
 	__delete_from_swap_cache(page);
-	spin_unlock_irq(&swapper_space.tree_lock);
+	write_unlock_irq(&swapper_space.tree_lock);
 
 	swap_free(entry);
 	page_cache_release(page);
@@ -310,13 +310,13 @@
 {
 	struct page *page;
 
-	spin_lock_irq(&swapper_space.tree_lock);
+	read_lock_irq(&swapper_space.tree_lock);
 	page = radix_tree_lookup(&swapper_space.page_tree, entry.val);
 	if (page) {
 		page_cache_get(page);
 		INC_CACHE_INFO(find_success);
 	}
-	spin_unlock_irq(&swapper_space.tree_lock);
+	read_unlock_irq(&swapper_space.tree_lock);
 	INC_CACHE_INFO(find_total);
 	return page;
 }
@@ -339,12 +339,12 @@
 		 * called after lookup_swap_cache() failed, re-calling
 		 * that would confuse statistics.
 		 */
-		spin_lock_irq(&swapper_space.tree_lock);
+		read_lock_irq(&swapper_space.tree_lock);
 		found_page = radix_tree_lookup(&swapper_space.page_tree,
 						entry.val);
 		if (found_page)
 			page_cache_get(found_page);
-		spin_unlock_irq(&swapper_space.tree_lock);
+		read_unlock_irq(&swapper_space.tree_lock);
 		if (found_page)
 			break;
 
--- diff/mm/swapfile.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/swapfile.c	2004-05-27 18:34:19.000000000 +0100
@@ -290,10 +290,10 @@
 		/* Is the only swap cache user the cache itself? */
 		if (p->swap_map[swp_offset(entry)] == 1) {
 			/* Recheck the page count with the swapcache lock held.. */
-			spin_lock_irq(&swapper_space.tree_lock);
+			write_lock_irq(&swapper_space.tree_lock);
 			if (page_count(page) == 2)
 				retval = 1;
-			spin_unlock_irq(&swapper_space.tree_lock);
+			write_unlock_irq(&swapper_space.tree_lock);
 		}
 		swap_info_put(p);
 	}
@@ -361,13 +361,13 @@
 	retval = 0;
 	if (p->swap_map[swp_offset(entry)] == 1) {
 		/* Recheck the page count with the swapcache lock held.. */
-		spin_lock_irq(&swapper_space.tree_lock);
+		write_lock_irq(&swapper_space.tree_lock);
 		if ((page_count(page) == 2) && !PageWriteback(page)) {
 			__delete_from_swap_cache(page);
 			SetPageDirty(page);
 			retval = 1;
 		}
-		spin_unlock_irq(&swapper_space.tree_lock);
+		write_unlock_irq(&swapper_space.tree_lock);
 	}
 	swap_info_put(p);
 
@@ -391,12 +391,12 @@
 	p = swap_info_get(entry);
 	if (p) {
 		if (swap_entry_free(p, swp_offset(entry)) == 1) {
-			spin_lock_irq(&swapper_space.tree_lock);
+			read_lock_irq(&swapper_space.tree_lock);
 			page = radix_tree_lookup(&swapper_space.page_tree,
 				entry.val);
 			if (page && TestSetPageLocked(page))
 				page = NULL;
-			spin_unlock_irq(&swapper_space.tree_lock);
+			read_unlock_irq(&swapper_space.tree_lock);
 		}
 		swap_info_put(p);
 	}
--- diff/mm/truncate.c	2004-05-19 22:13:12.000000000 +0100
+++ source/mm/truncate.c	2004-05-27 18:34:19.000000000 +0100
@@ -74,13 +74,13 @@
 	if (PagePrivate(page) && !try_to_release_page(page, 0))
 		return 0;
 
-	spin_lock_irq(&mapping->tree_lock);
+	write_lock_irq(&mapping->tree_lock);
 	if (PageDirty(page)) {
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		return 0;
 	}
 	__remove_from_page_cache(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	write_unlock_irq(&mapping->tree_lock);
 	ClearPageUptodate(page);
 	page_cache_release(page);	/* pagecache ref */
 	return 1;
@@ -243,6 +243,10 @@
  * where the page is seen to be mapped into process pagetables.  In that case,
  * the page is marked clean but is left attached to its address_space.
  *
+ * The page is also marked not uptodate so that a subsequent pagefault will
+ * perform I/O to bringthe page's contents back into sync with its backing
+ * store.
+ *
  * FIXME: invalidate_inode_pages2() is probably trivially livelockable.
  */
 void invalidate_inode_pages2(struct address_space *mapping)
@@ -260,10 +264,12 @@
 			if (page->mapping == mapping) {	/* truncate race? */
 				wait_on_page_writeback(page);
 				next = page->index + 1;
-				if (page_mapped(page))
+				if (page_mapped(page)) {
 					clear_page_dirty(page);
-				else
+					ClearPageUptodate(page);
+				} else {
 					invalidate_complete_page(mapping, page);
+				}
 			}
 			unlock_page(page);
 		}
--- diff/mm/vmalloc.c	2004-05-19 22:13:12.000000000 +0100
+++ source/mm/vmalloc.c	2004-05-27 18:34:19.000000000 +0100
@@ -17,7 +17,6 @@
 #include <linux/vmalloc.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 
@@ -284,6 +283,7 @@
 
 	if ((PAGE_SIZE-1) & (unsigned long)addr) {
 		printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
+		WARN_ON(1);
 		return;
 	}
 
@@ -291,6 +291,7 @@
 	if (unlikely(!area)) {
 		printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n",
 				addr);
+		WARN_ON(1);
 		return;
 	}
 	
--- diff/mm/vmscan.c	2004-05-27 13:41:27.000000000 +0100
+++ source/mm/vmscan.c	2004-05-27 18:34:19.000000000 +0100
@@ -33,7 +33,6 @@
 #include <linux/cpu.h>
 #include <linux/notifier.h>
 
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
 
@@ -374,7 +373,17 @@
 					/* synchronous write or broken a_ops? */
 					ClearPageReclaim(page);
 				}
-				goto keep;
+				if (PageWriteback(page) || PageDirty(page))
+					goto keep;
+				/*
+				 * A synchronous write - probably a ramdisk.  Go
+				 * ahead and try to reclaim the page.
+				 */
+				if (TestSetPageLocked(page))
+					goto keep;
+				if (PageDirty(page) || PageWriteback(page))
+					goto keep_locked;
+				mapping = page_mapping(page);
 			}
 		}
 
@@ -396,7 +405,7 @@
 		 * the pages which were not successfully invalidated in
 		 * truncate_complete_page().  We try to drop those buffers here
 		 * and if that worked, and the page is no longer mapped into
-		 * process address space (page_count == 0) it can be freed.
+		 * process address space (page_count == 1) it can be freed.
 		 * Otherwise, leave the page on the LRU so it is swappable.
 		 */
 		if (PagePrivate(page)) {
@@ -409,7 +418,7 @@
 		if (!mapping)
 			goto keep_locked;	/* truncate got there first */
 
-		spin_lock_irq(&mapping->tree_lock);
+		write_lock_irq(&mapping->tree_lock);
 
 		/*
 		 * The non-racy check for busy page.  It is critical to check
@@ -417,7 +426,7 @@
 		 * not in use by anybody. 	(pagecache + us == 2)
 		 */
 		if (page_count(page) != 2 || PageDirty(page)) {
-			spin_unlock_irq(&mapping->tree_lock);
+			write_unlock_irq(&mapping->tree_lock);
 			goto keep_locked;
 		}
 
@@ -425,7 +434,7 @@
 		if (PageSwapCache(page)) {
 			swp_entry_t swap = { .val = page->private };
 			__delete_from_swap_cache(page);
-			spin_unlock_irq(&mapping->tree_lock);
+			write_unlock_irq(&mapping->tree_lock);
 			swap_free(swap);
 			__put_page(page);	/* The pagecache ref */
 			goto free_it;
@@ -433,7 +442,7 @@
 #endif /* CONFIG_SWAP */
 
 		__remove_from_page_cache(page);
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		__put_page(page);
 
 free_it:
--- diff/net/8021q/vlan.h	2004-05-19 22:13:12.000000000 +0100
+++ source/net/8021q/vlan.h	2004-05-27 18:34:19.000000000 +0100
@@ -7,7 +7,7 @@
 /* #define VLAN_DEBUG */
 
 #define VLAN_ERR KERN_ERR
-#define VLAN_INF KERN_ALERT
+#define VLAN_INF KERN_INFO
 #define VLAN_DBG KERN_ALERT /* change these... to debug, having a hard time
                              * changing the log level at run-time..for some reason.
                              */
--- diff/net/Kconfig	2004-05-19 22:13:12.000000000 +0100
+++ source/net/Kconfig	2004-05-27 18:34:19.000000000 +0100
@@ -650,18 +650,17 @@
 
 endmenu
 
+config KGDBOE
+	def_bool (X86 || IA64) && KGDB
+
 config NETPOLL
-	def_bool NETCONSOLE
+	def_bool NETCONSOLE || KGDBOE
 
 config NETPOLL_RX
-	bool "Netpoll support for trapping incoming packets"
-	default n
-	depends on NETPOLL
+	def_bool KGDBOE
 
 config NETPOLL_TRAP
-	bool "Netpoll traffic trapping"
-	default n
-	depends on NETPOLL
+	def_bool KGDBOE
 
 config NET_POLL_CONTROLLER
 	def_bool NETPOLL
--- diff/net/bluetooth/rfcomm/core.c	2004-05-27 13:41:27.000000000 +0100
+++ source/net/bluetooth/rfcomm/core.c	2004-05-27 18:34:19.000000000 +0100
@@ -470,32 +470,33 @@
 	if (!s)
 		return NULL;
 	memset(s, 0, sizeof(*s));
-	
+
 	BT_DBG("session %p sock %p", s, sock);
 
 	INIT_LIST_HEAD(&s->dlcs);
 	s->state = state;
 	s->sock  = sock;
 
-	s->mtu   = RFCOMM_DEFAULT_MTU;
-	s->cfc   = RFCOMM_CFC_UNKNOWN;
-	
-	list_add(&s->list, &session_list);
+	s->mtu = RFCOMM_DEFAULT_MTU;
+	s->cfc = RFCOMM_CFC_UNKNOWN;
 
-	/* Do not increment module usage count for listeting sessions.
-	 * Otherwise we won't be able to unload the module.
-	 * Non listening session are added either by a socket or a TTYs
-	 * which means that we already hold refcount to this module.
-	 */
+	/* Do not increment module usage count for listening sessions.
+	 * Otherwise we won't be able to unload the module. */
 	if (state != BT_LISTEN)
-		__module_get(THIS_MODULE);
+		if (!try_module_get(THIS_MODULE)) {
+			kfree(s);
+			return NULL;
+		}
+
+	list_add(&s->list, &session_list);
+
 	return s;
 }
 
 void rfcomm_session_del(struct rfcomm_session *s)
 {
 	int state = s->state;
-	
+
 	BT_DBG("session %p state %ld", s, s->state);
 
 	list_del(&s->list);
--- diff/net/core/dev.c	2004-05-27 13:41:27.000000000 +0100
+++ source/net/core/dev.c	2004-05-27 18:34:19.000000000 +0100
@@ -1527,7 +1527,6 @@
 }
 #endif
 
-
 /**
  *	netif_rx	-	post buffer to the network code
  *	@skb: buffer to post
@@ -1847,7 +1846,6 @@
 	unsigned long start_time = jiffies;
 	int budget = netdev_max_backlog;
 
-	
 	local_irq_disable();
 
 	while (!list_empty(&queue->poll_list)) {
@@ -1873,6 +1871,10 @@
 			dev_put(dev);
 			local_irq_disable();
 		}
+
+#ifdef CONFIG_KGDBOE
+		kgdb_process_breakpoint();
+#endif
 	}
 out:
 	local_irq_enable();
--- diff/net/core/net-sysfs.c	2004-05-19 22:13:13.000000000 +0100
+++ source/net/core/net-sysfs.c	2004-05-27 18:34:19.000000000 +0100
@@ -20,9 +20,9 @@
 #define to_class_dev(obj) container_of(obj,struct class_device,kobj)
 #define to_net_dev(class) container_of(class, struct net_device, class_dev)
 
-static const char *fmt_hex = "%#x\n";
-static const char *fmt_dec = "%d\n";
-static const char *fmt_ulong = "%lu\n";
+static const char fmt_hex[] = "%#x\n";
+static const char fmt_dec[] = "%d\n";
+static const char fmt_ulong[] = "%lu\n";
 
 static inline int dev_isalive(const struct net_device *dev) 
 {
--- diff/net/ipv4/xfrm4_state.c	2004-05-19 22:13:14.000000000 +0100
+++ source/net/ipv4/xfrm4_state.c	2004-05-27 18:34:19.000000000 +0100
@@ -83,9 +83,7 @@
 			    break;
 		    }
 	}
-	if (x0) {
-		xfrm_state_hold(x0);
-	} else if (create && (x0 = xfrm_state_alloc()) != NULL) {
+	if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) {
 		x0->sel.daddr.a4 = daddr->a4;
 		x0->sel.saddr.a4 = saddr->a4;
 		x0->sel.prefixlen_d = 32;
@@ -100,11 +98,14 @@
 		x0->props.family = AF_INET;
 		x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
 		xfrm_state_hold(x0);
-		mod_timer(&x0->timer, jiffies + XFRM_ACQ_EXPIRES*HZ);
+		x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
+		add_timer(&x0->timer);
 		xfrm_state_hold(x0);
 		list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h);
 		wake_up(&km_waitq);
 	}
+	if (x0)
+		xfrm_state_hold(x0);
 	return x0;
 }
 
--- diff/net/ipv6/xfrm6_state.c	2004-05-19 22:13:15.000000000 +0100
+++ source/net/ipv6/xfrm6_state.c	2004-05-27 18:34:19.000000000 +0100
@@ -90,9 +90,7 @@
 			    break;
 		    }
 	}
-	if (x0) {
-		xfrm_state_hold(x0);
-	} else if (create && (x0 = xfrm_state_alloc()) != NULL) {
+	if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) {
 		ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6,
 			       (struct in6_addr *)daddr);
 		ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6,
@@ -110,11 +108,14 @@
 		x0->props.reqid = reqid;
 		x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
 		xfrm_state_hold(x0);
-		mod_timer(&x0->timer, jiffies + XFRM_ACQ_EXPIRES*HZ);
+		x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
+		add_timer(&x0->timer);
 		xfrm_state_hold(x0);
 		list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h);
 		wake_up(&km_waitq);
 	}
+	if (x0)
+		xfrm_state_hold(x0);
 	return x0;
 }
 
--- diff/net/irda/ircomm/ircomm_tty.c	2004-05-27 13:41:27.000000000 +0100
+++ source/net/irda/ircomm/ircomm_tty.c	2004-05-27 18:34:19.000000000 +0100
@@ -721,8 +721,10 @@
 		kbuf = kmalloc(count, GFP_KERNEL);
 		if (kbuf == NULL)
 			return -ENOMEM;
-		if (copy_from_user(kbuf, ubuf, count))
+		if (copy_from_user(kbuf, ubuf, count)) {
+			kfree(kbuf);
 			return -EFAULT;
+		}
 	} else
 		/* The buffer is already in kernel space */
 		kbuf = (unsigned char *) ubuf;
@@ -779,6 +781,8 @@
 					    self->max_header_size);
 			if (!skb) {
 				spin_unlock_irqrestore(&self->spinlock, flags);
+	                        if (from_user)
+		                        kfree(kbuf);
 				return -ENOBUFS;
 			}
 			skb_reserve(skb, self->max_header_size);
--- diff/net/key/af_key.c	2004-05-19 22:13:15.000000000 +0100
+++ source/net/key/af_key.c	2004-05-27 18:34:19.000000000 +0100
@@ -1976,7 +1976,7 @@
 	memset(&sel, 0, sizeof(sel));
 
 	sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 
-	pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
+	sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
 	sel.prefixlen_s = sa->sadb_address_prefixlen;
 	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
 	sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
--- diff/net/sctp/sm_make_chunk.c	2004-05-19 22:13:17.000000000 +0100
+++ source/net/sctp/sm_make_chunk.c	2004-05-27 18:34:19.000000000 +0100
@@ -1834,23 +1834,28 @@
 	/* Allocate storage for the negotiated streams if it is not a temporary 	 * association.
 	 */
 	if (!asoc->temp) {
-		sctp_assoc_t assoc_id;
+		int assoc_id;
+		int error;
 
 		asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams,
 					       asoc->c.sinit_num_ostreams, gfp);
 		if (!asoc->ssnmap)
 			goto clean_up;
 
-		do {
-			if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
-				goto clean_up;
-			spin_lock_bh(&sctp_assocs_id_lock);
-			assoc_id = (sctp_assoc_t)idr_get_new(&sctp_assocs_id,
-							     (void *)asoc);
-			spin_unlock_bh(&sctp_assocs_id_lock);
-		} while (unlikely((int)assoc_id == -1));
+	retry:
+		if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
+			goto clean_up;
+		spin_lock_bh(&sctp_assocs_id_lock);
+		error = idr_get_new(&sctp_assocs_id,
+				    (void *)asoc,
+				    &assoc_id);
+		spin_unlock_bh(&sctp_assocs_id_lock);
+		if (error == -EAGAIN)
+			goto retry;
+		else if (error)
+			goto clean_up;
 
-		asoc->assoc_id = assoc_id;
+		asoc->assoc_id = (sctp_assoc_t) assoc_id;
 	}
 
 	/* ADDIP Section 4.1 ASCONF Chunk Procedures
--- diff/net/sunrpc/cache.c	2004-05-27 13:41:27.000000000 +0100
+++ source/net/sunrpc/cache.c	2004-05-27 18:34:19.000000000 +0100
@@ -910,9 +910,8 @@
 {
 	if (detail->last_warn != detail->last_close) {
 		detail->last_warn = detail->last_close;
-		printk(KERN_WARNING "nfsd: nobody listening for %s upcall;"
-				" has some daemon %s?\n", detail->name,
-		      		detail->last_close?"died" : "not been started");
+		if (detail->warn_no_listener)
+			detail->warn_no_listener(detail);
 	}
 }
 
--- diff/net/xfrm/xfrm_state.c	2004-05-27 13:41:27.000000000 +0100
+++ source/net/xfrm/xfrm_state.c	2004-05-27 18:34:19.000000000 +0100
@@ -221,13 +221,9 @@
 		if (atomic_read(&x->refcnt) > 2)
 			xfrm_flush_bundles();
 
-		/* All xfrm_state objects are created by one of two possible
-		 * paths:
-		 *
-		 * 2) xfrm_state_lookup --> xfrm_state_insert
-		 *
-		 * The xfrm_state_lookup or xfrm_state_alloc call gives a
-		 * reference, and that is what we are dropping here.
+		/* All xfrm_state objects are created by xfrm_state_alloc.
+		 * The xfrm_state_alloc call gives a reference, and that
+		 * is what we are dropping here.
 		 */
 		atomic_dec(&x->refcnt);
 	}
@@ -331,14 +327,8 @@
 		}
 	}
 
-	if (best) {
-		xfrm_state_hold(best);
-		spin_unlock_bh(&xfrm_state_lock);
-		return best;
-	}
-
-	x = NULL;
-	if (!error && !acquire_in_progress &&
+	x = best;
+	if (!x && !error && !acquire_in_progress &&
 	    ((x = xfrm_state_alloc()) != NULL)) {
 		/* Initialize temporary selector matching only
 		 * to current session. */
@@ -355,7 +345,8 @@
 			}
 			x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
 			xfrm_state_hold(x);
-			mod_timer(&x->timer, XFRM_ACQ_EXPIRES*HZ);
+			x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
+			add_timer(&x->timer);
 		} else {
 			x->km.state = XFRM_STATE_DEAD;
 			xfrm_state_put(x);
@@ -363,10 +354,12 @@
 			error = 1;
 		}
 	}
-	spin_unlock_bh(&xfrm_state_lock);
-	if (!x)
+	if (x)
+		xfrm_state_hold(x);
+	else
 		*err = acquire_in_progress ? -EAGAIN :
 			(error ? -ESRCH : -ENOMEM);
+	spin_unlock_bh(&xfrm_state_lock);
 	return x;
 }
 
--- diff/scripts/mk_elfconfig.c	2004-05-19 22:13:18.000000000 +0100
+++ source/scripts/mk_elfconfig.c	2004-05-27 18:34:19.000000000 +0100
@@ -55,7 +55,7 @@
 	else
 		abort();
 
-	if (strcmp(argv[1], "v850") == 0)
+	if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0))
 		printf("#define MODULE_SYMBOL_PREFIX \"_\"\n");
 	else 
 		printf("#define MODULE_SYMBOL_PREFIX \"\"\n");
--- diff/sound/arm/sa11xx-uda1341.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/arm/sa11xx-uda1341.c	2004-05-27 18:34:19.000000000 +0100
@@ -21,7 +21,7 @@
  *                              merged HAL layer (patches from Brian)
  */
 
-/* $Id: sa11xx-uda1341.c,v 1.13 2004/03/02 15:32:35 perex Exp $ */
+/* $Id: sa11xx-uda1341.c,v 1.15 2004/05/03 17:36:50 tiwai Exp $ */
 
 /***************************************************************************************************
 *
@@ -62,6 +62,7 @@
 #include <linux/config.h>
 #include <sound/driver.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/ioctl.h>
@@ -112,7 +113,7 @@
 
 static char *id = NULL;	/* ID for this card */
 
-MODULE_PARM(id, "s");
+module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
 
 #define chip_t sa11xx_uda1341_t
@@ -136,7 +137,6 @@
 }audio_stream_t;
 
 typedef struct snd_card_sa11xx_uda1341 {
-	struct pm_dev *pm_dev;        
 	snd_card_t *card;
 	struct l3_client *uda1341;
 	snd_pcm_t *pcm;
@@ -867,12 +867,10 @@
 
 #ifdef CONFIG_PM
 
-static void snd_sa11xx_uda1341_suspend(sa11xx_uda1341_t *chip)
+static int snd_sa11xx_uda1341_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	sa11xx_uda1341_t *chip = snd_magic_cast(sa11x_uda1341_t, card->pm_private_data, return -EINVAL);
 
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
 	snd_pcm_suspend_all(chip->pcm);
 #ifdef HH_VERSION	
 	sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
@@ -883,14 +881,13 @@
 	l3_command(chip->uda1341, CMD_SUSPEND, NULL);
 	sa11xx_uda1341_audio_shutdown(chip);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void snd_sa11xx_uda1341_resume(sa11xx_uda1341_t *chip)
+static int snd_sa11xx_uda1341_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	sa11xx_uda1341_t *chip = snd_magic_cast(sa11x_uda1341_t, card->pm_private_data, return -EINVAL);
 
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
 	sa11xx_uda1341_audio_init(chip);
 	l3_command(chip->uda1341, CMD_RESUME, NULL);
 #ifdef HH_VERSION	
@@ -900,50 +897,14 @@
 	//FIXME
 #endif
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int sa11xx_uda1341_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
-{
-	sa11xx_uda1341_t *chip = pm_dev->data;
-        
-	switch (req) {
-	case PM_SUSPEND: /* enter D1-D3 */
-		snd_sa11xx_uda1341_suspend(chip);
-		break;
-	case PM_RESUME:  /* enter D0 */
-		snd_sa11xx_uda1341_resume(chip);
-		break;
-	}
-	return 0;
-}
-
-static int sa11xx_uda1341_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	sa11xx_uda1341_t *chip = snd_magic_cast(sa11xx_uda1341_t, card->power_state_private_data, return);
-
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		snd_sa11xx_uda1341_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		snd_sa11xx_uda1341_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
-
 #endif /* COMFIG_PM */
 
 void snd_sa11xx_uda1341_free(snd_card_t *card)
 {
 	sa11xx_uda1341_t *chip = snd_magic_cast(sa11xx_uda1341_t, card->private_data, return);
 
-	pm_unregister(chip->pm_dev);
 	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
 	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
 	sa11xx_uda1341 = NULL;
@@ -984,15 +945,10 @@
 	if ((err = snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341, 0)) < 0)
 		goto nodev;
         
-       
-#ifdef CONFIG_PM
-	card->power_state_private_data = sa11xx_uda1341;
-	card->set_power_state = sa11xx_uda1341_set_power_state;
-	sa11xx_uda1341->pm_dev = pm_register(PM_SYS_DEV, 0, sa11xx_uda1341_pm_callback);
-	if (sa11xx_uda1341->pm_dev)
-		sa11xx_uda1341->pm_dev->data = sa11xx_uda1341;
-#endif
-        
+	snd_card_set_dev_pm_callback(card, PM_SYS_DEV,
+				     snd_sa11xx_uda1341_suspend, snd_sa11_uda1341_resume,
+				     sa11xx_uda1341);
+
 	strcpy(card->driver, "UDA1341");
 	strcpy(card->shortname, "H3600 UDA1341TS");
 	sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS");
--- diff/sound/core/Kconfig	2004-05-27 13:41:27.000000000 +0100
+++ source/sound/core/Kconfig	2004-05-27 18:34:19.000000000 +0100
@@ -1,8 +1,4 @@
 # ALSA soundcard-configuration
-config SND_BIT32_EMUL
-	tristate "Emulation for 32-bit applications"
-	depends on SND && SND_PCM && (MIPS64 || SPARC64 || PPC64 || X86_64 && IA32_EMULATION)
-
 config SND_TIMER
 	tristate
 
@@ -59,6 +55,17 @@
 	  Say 'Y' to enable OSS sequencer emulation (both /dev/sequencer and
 	  /dev/music interfaces).
 
+config SND_BIT32_EMUL
+	tristate "Emulation for 32-bit applications"
+	depends on SND && (MIPS64 || SPARC64 || PPC64 || X86_64 && IA32_EMULATION)
+	select SND_PCM
+	select SND_RAWMIDI
+	select SND_TIMER
+	select SND_HWDEP
+	help
+	  Say 'Y' or 'M' to enable the emulation for 32-bit ALSA-native
+	  applications.
+
 config SND_RTCTIMER
 	tristate "RTC Timer support"
 	depends on SND && RTC
--- diff/sound/core/control.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/control.c	2004-05-27 18:34:19.000000000 +0100
@@ -995,6 +995,33 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+/*
+ * change the power state
+ */
+static int snd_ctl_set_power_state(snd_card_t *card, unsigned int power_state)
+{
+	switch (power_state) {
+	case SNDRV_CTL_POWER_D0:
+	case SNDRV_CTL_POWER_D1:
+	case SNDRV_CTL_POWER_D2:
+		if (card->power_state != power_state)
+			/* FIXME: pass the correct state value */
+			card->pm_resume(card, 0);
+		break;
+	case SNDRV_CTL_POWER_D3hot:
+	case SNDRV_CTL_POWER_D3cold:
+		if (card->power_state != power_state)
+			/* FIXME: pass the correct state value */
+			card->pm_suspend(card, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+#endif
+
 static int snd_ctl_ioctl(struct inode *inode, struct file *file,
 			 unsigned int cmd, unsigned long arg)
 {
@@ -1038,9 +1065,9 @@
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 #ifdef CONFIG_PM
-		if (card->set_power_state) {
+		if (card->pm_suspend && card->pm_resume) {
 			snd_power_lock(card);
-			err = card->set_power_state(card, err);
+			err = snd_ctl_set_power_state(card, err);
 			snd_power_unlock(card);
 		} else
 #endif
--- diff/sound/core/init.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/init.c	2004-05-27 18:34:19.000000000 +0100
@@ -26,6 +26,8 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/ctype.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -254,6 +256,12 @@
 
 #ifdef CONFIG_PM
 	wake_up(&card->power_sleep);
+#ifdef CONFIG_ISA
+	if (card->pm_dev) {
+		pm_unregister(card->pm_dev);
+		card->pm_dev = NULL;
+	}
+#endif
 #endif
 
 	/* wait, until all devices are ready for the free operation */
@@ -708,4 +716,93 @@
 	remove_wait_queue(&card->power_sleep, &wait);
 	return result;
 }
+
+/**
+ * snd_card_set_pm_callback - set the PCI power-management callbacks
+ * @card: soundcard structure
+ * @suspend: suspend callback function
+ * @resume: resume callback function
+ * @private_data: private data to pass to the callback functions
+ *
+ * Sets the power-management callback functions of the card.
+ * These callbacks are called from ALSA's common PCI suspend/resume
+ * handler and from the control API.
+ */
+int snd_card_set_pm_callback(snd_card_t *card,
+			     int (*suspend)(snd_card_t *, unsigned int),
+			     int (*resume)(snd_card_t *, unsigned int),
+			     void *private_data)
+{
+	card->pm_suspend = suspend;
+	card->pm_resume = resume;
+	card->pm_private_data = private_data;
+	return 0;
+}
+
+static int snd_generic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	snd_card_t *card = dev->data;
+
+	switch (rqst) {
+	case PM_SUSPEND:
+		/* FIXME: the correct state value? */
+		card->pm_suspend(card, 0);
+		break;
+	case PM_RESUME:
+		/* FIXME: the correct state value? */
+		card->pm_resume(card, 0);
+		break;
+	}
+	return 0;
+}
+
+/**
+ * snd_card_set_dev_pm_callback - set the generic power-management callbacks
+ * @card: soundcard structure
+ * @type: PM device type (PM_XXX)
+ * @suspend: suspend callback function
+ * @resume: resume callback function
+ * @private_data: private data to pass to the callback functions
+ *
+ * Registers the power-management and sets the lowlevel callbacks for
+ * the given card with the given PM type.  These callbacks are called
+ * from the ALSA's common PM handler and from the control API.
+ */
+int snd_card_set_dev_pm_callback(snd_card_t *card, int type,
+				 int (*suspend)(snd_card_t *, unsigned int),
+				 int (*resume)(snd_card_t *, unsigned int),
+				 void *private_data)
+{
+	card->pm_dev = pm_register(type, 0, snd_generic_pm_callback);
+	if (! card->pm_dev)
+		return -ENOMEM;
+	card->pm_dev->data = card;
+	snd_card_set_pm_callback(card, suspend, resume, private_data);
+	return 0;
+}
+
+#ifdef CONFIG_PCI
+int snd_card_pci_suspend(struct pci_dev *dev, u32 state)
+{
+	snd_card_t *card = pci_get_drvdata(dev);
+	if (! card || ! card->pm_suspend)
+		return 0;
+	if (card->power_state == SNDRV_CTL_POWER_D3hot)
+		return 0;
+	/* FIXME: correct state value? */
+	return card->pm_suspend(card, 0);
+}
+
+int snd_card_pci_resume(struct pci_dev *dev)
+{
+	snd_card_t *card = pci_get_drvdata(dev);
+	if (! card || ! card->pm_resume)
+		return 0;
+	if (card->power_state == SNDRV_CTL_POWER_D0)
+		return 0;
+	/* FIXME: correct state value? */
+	return card->pm_resume(card, 0);
+}
+#endif
+
 #endif /* CONFIG_PM */
--- diff/sound/core/memalloc.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/memalloc.c	2004-05-27 18:34:19.000000000 +0100
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/moduleparam.h>
 #include <asm/semaphore.h>
 #include <sound/memalloc.h>
 #ifdef CONFIG_SBUS
@@ -45,7 +46,8 @@
 #define SNDRV_CARDS	8
 #endif
 static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+static int boot_devs;
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
 
 /*
@@ -89,32 +91,7 @@
  *  Hacks
  */
 
-static void *snd_dma_alloc_coherent1(struct device *dev, size_t size,
-				     dma_addr_t *dma_handle, int flags)
-{
-	if (dev)
-		return dma_alloc_coherent(dev, size, dma_handle, flags);
-	else /* FIXME: dma_alloc_coherent does't always accept dev=NULL */
-		return pci_alloc_consistent(NULL, size, dma_handle);
-}
-
-static void snd_dma_free_coherent1(struct device *dev, size_t size, void *dma_addr,
-				   dma_addr_t dma_handle)
-{
-	if (dev)
-		return dma_free_coherent(dev, size, dma_addr, dma_handle);
-	else
-		return pci_free_consistent(NULL, size, dma_addr, dma_handle);
-}
-
-#undef dma_alloc_coherent
-#define dma_alloc_coherent snd_dma_alloc_coherent1
-#undef dma_free_coherent
-#define dma_free_coherent snd_dma_free_coherent1
-
-
 #if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
-
 /*
  * A hack to allocate large buffers via dma_alloc_coherent()
  *
@@ -135,14 +112,17 @@
 					 dma_addr_t *dma_handle, int flags)
 {
 	void *ret;
-	u64 dma_mask;
+	u64 dma_mask, coherent_dma_mask;
 
 	if (dev == NULL || !dev->dma_mask)
 		return dma_alloc_coherent(dev, size, dma_handle, flags);
 	dma_mask = *dev->dma_mask;
+	coherent_dma_mask = dev->coherent_dma_mask;
 	*dev->dma_mask = 0xffffffff; 	/* do without masking */
+	dev->coherent_dma_mask = 0xffffffff; 	/* do without masking */
 	ret = dma_alloc_coherent(dev, size, dma_handle, flags);
 	*dev->dma_mask = dma_mask;	/* restore */
+	dev->coherent_dma_mask = coherent_dma_mask;	/* restore */
 	if (ret) {
 		/* obtained address is out of range? */
 		if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) {
@@ -152,8 +132,12 @@
 		}
 	} else {
 		/* wish to success now with the proper mask... */
-		if (dma_mask != 0xffffffffUL)
+		if (dma_mask != 0xffffffffUL) {
+			/* allocation with GFP_ATOMIC to avoid the long stall */
+			flags &= ~GFP_KERNEL;
+			flags |= GFP_ATOMIC;
 			ret = dma_alloc_coherent(dev, size, dma_handle, flags);
+		}
 	}
 	return ret;
 }
@@ -842,25 +826,6 @@
 module_exit(snd_mem_exit)
 
 
-#ifndef MODULE
-
-/* format is: snd-page-alloc=enable */
-
-static int __init snd_mem_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str,&enable[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-page-alloc=", snd_mem_setup);
-
-#endif
-
 /*
  * exports
  */
--- diff/sound/core/oss/pcm_oss.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/oss/pcm_oss.c	2004-05-27 18:34:19.000000000 +0100
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/vmalloc.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/pcm.h>
@@ -45,17 +46,18 @@
 static int dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
 static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
 static int nonblock_open;
+static int boot_devs;
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>");
 MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");
 MODULE_LICENSE("GPL");
-MODULE_PARM(dsp_map, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dsp_map, int, boot_devs, 0444);
 MODULE_PARM_DESC(dsp_map, "PCM device number assigned to 1st OSS device.");
 MODULE_PARM_SYNTAX(dsp_map, "default:0,skill:advanced");
-MODULE_PARM(adsp_map, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(adsp_map, int, boot_devs, 0444);
 MODULE_PARM_DESC(adsp_map, "PCM device number assigned to 2nd OSS device.");
 MODULE_PARM_SYNTAX(adsp_map, "default:1,skill:advanced");
-MODULE_PARM(nonblock_open, "i");
+module_param(nonblock_open, bool, 0644);
 MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices.");
 MODULE_PARM_SYNTAX(nonblock_open, "default:0,skill:advanced");
 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM);
@@ -1514,14 +1516,14 @@
 		runtime->oss.prev_hw_ptr_interrupt = delay;
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			snd_pcm_oss_simulate_fill(substream, delay);
-		info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr);
+		info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
 	} else {
 		delay = snd_pcm_oss_bytes(substream, delay) + fixup;
 		info.blocks = delay / runtime->oss.period_bytes;
 		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-			info.bytes = runtime->oss.bytes - delay;
+			info.bytes = (runtime->oss.bytes - delay) & INT_MAX;
 		else
-			info.bytes = runtime->oss.bytes + delay;
+			info.bytes = (runtime->oss.bytes + delay) & INT_MAX;
 	}
 	if (copy_to_user(_info, &info, sizeof(info)))
 		return -EFAULT;
@@ -2510,24 +2512,3 @@
 
 module_init(alsa_pcm_oss_init)
 module_exit(alsa_pcm_oss_exit)
-
-#ifndef MODULE
-
-/* format is: snd-pcm-oss=dsp_map,adsp_map[,nonblock_open] */
-
-static int __init alsa_pcm_oss_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str,&dsp_map[nr_dev]) == 2 &&
-	       get_option(&str,&adsp_map[nr_dev]) == 2);
-	(void)(get_option(&str,&nonblock_open) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-pcm-oss=", alsa_pcm_oss_setup);
-
-#endif /* !MODULE */
--- diff/sound/core/pcm_memory.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/pcm_memory.c	2004-05-27 18:34:19.000000000 +0100
@@ -23,18 +23,19 @@
 #include <asm/io.h>
 #include <linux/time.h>
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
 #include <sound/initval.h>
 
 static int preallocate_dma = 1;
-MODULE_PARM(preallocate_dma, "i");
+module_param(preallocate_dma, int, 0444);
 MODULE_PARM_DESC(preallocate_dma, "Preallocate DMA memory when the PCM devices are initialized.");
 MODULE_PARM_SYNTAX(preallocate_dma, SNDRV_BOOLEAN_TRUE_DESC);
 
 static int maximum_substreams = 4;
-MODULE_PARM(maximum_substreams, "i");
+module_param(maximum_substreams, int, 0444);
 MODULE_PARM_DESC(maximum_substreams, "Maximum substreams with preallocated DMA memory.");
 MODULE_PARM_SYNTAX(maximum_substreams, SNDRV_BOOLEAN_TRUE_DESC);
 
@@ -223,9 +224,13 @@
  */
 static inline void setup_pcm_id(snd_pcm_substream_t *subs)
 {
-	if (! subs->dma_device.id)
+	if (! subs->dma_device.id) {
 		subs->dma_device.id = subs->pcm->device << 16 |
 			subs->stream << 8 | (subs->number + 1);
+		if (subs->dma_device.type == SNDRV_DMA_TYPE_CONTINUOUS ||
+		    subs->dma_device.dev == NULL)
+			subs->dma_device.id |= (subs->pcm->card->number + 1) << 24;
+	}
 }
 
 /**
--- diff/sound/core/pcm_misc.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/pcm_misc.c	2004-05-27 18:34:19.000000000 +0100
@@ -230,7 +230,7 @@
 		return 64;
 	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
 	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
-		return 24;
+		return 32;
 	case SNDRV_PCM_FORMAT_MU_LAW:
 	case SNDRV_PCM_FORMAT_A_LAW:
 		return 8;
--- diff/sound/core/pcm_native.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/pcm_native.c	2004-05-27 18:34:19.000000000 +0100
@@ -1038,7 +1038,7 @@
 
 	snd_power_lock(card);
 	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
-		return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0, 0);
+		res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0, 0);
 	snd_power_unlock(card);
 	return res;
 }
@@ -2335,6 +2335,45 @@
 	return err;
 }
 		
+static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_sync_ptr *_sync_ptr)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct sndrv_pcm_sync_ptr sync_ptr;
+	volatile struct sndrv_pcm_mmap_status *status;
+	volatile struct sndrv_pcm_mmap_control *control;
+	int err;
+
+	memset(&sync_ptr, 0, sizeof(sync_ptr));
+	if (get_user(sync_ptr.flags, (unsigned int *) &(_sync_ptr->flags)))
+		return -EFAULT;
+	if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct sndrv_pcm_mmap_control)))
+		return -EFAULT;	
+	status = runtime->status;
+	control = runtime->control;
+	if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
+		err = snd_pcm_hwsync(substream);
+		if (err < 0)
+			return err;
+	}
+	snd_pcm_stream_lock_irq(substream);
+	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
+		control->appl_ptr = sync_ptr.c.control.appl_ptr;
+	else
+		sync_ptr.c.control.appl_ptr = control->appl_ptr;
+	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+		control->avail_min = sync_ptr.c.control.avail_min;
+	else
+		sync_ptr.c.control.avail_min = control->avail_min;
+	sync_ptr.s.status.state = status->state;
+	sync_ptr.s.status.hw_ptr = status->hw_ptr;
+	sync_ptr.s.status.tstamp = status->tstamp;
+	sync_ptr.s.status.suspended_state = status->suspended_state;
+	snd_pcm_stream_unlock_irq(substream);
+	if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
+		return -EFAULT;
+	return 0;
+}
+		
 static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
 				   unsigned int cmd, void *arg);
 static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
@@ -2388,6 +2427,8 @@
 		return snd_pcm_hwsync(substream);
 	case SNDRV_PCM_IOCTL_DELAY:
 		return snd_pcm_delay(substream, (snd_pcm_sframes_t *) arg);
+	case SNDRV_PCM_IOCTL_SYNC_PTR:
+		return snd_pcm_sync_ptr(substream, (struct sndrv_pcm_sync_ptr *) arg);
 	case SNDRV_PCM_IOCTL_HW_REFINE_OLD:
 		return snd_pcm_hw_refine_old_user(substream, (struct sndrv_pcm_hw_params_old *) arg);
 	case SNDRV_PCM_IOCTL_HW_PARAMS_OLD:
--- diff/sound/core/rawmidi.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/rawmidi.c	2004-05-27 18:34:19.000000000 +0100
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 #include <sound/rawmidi.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -40,10 +41,11 @@
 #ifdef CONFIG_SND_OSSEMUL
 static int midi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
 static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
-MODULE_PARM(midi_map, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+static int boot_devs;
+module_param_array(midi_map, int, boot_devs, 0444);
 MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
 MODULE_PARM_SYNTAX(midi_map, "default:0,skill:advanced");
-MODULE_PARM(amidi_map, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(amidi_map, int, boot_devs, 0444);
 MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device.");
 MODULE_PARM_SYNTAX(amidi_map, "default:1,skill:advanced");
 #endif /* CONFIG_SND_OSSEMUL */
@@ -1637,26 +1639,6 @@
 module_init(alsa_rawmidi_init)
 module_exit(alsa_rawmidi_exit)
 
-#ifndef MODULE
-#ifdef CONFIG_SND_OSSEMUL
-/* format is: snd-rawmidi=midi_map,amidi_map */
-
-static int __init alsa_rawmidi_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str,&midi_map[nr_dev]) == 2 &&
-	       get_option(&str,&amidi_map[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-rawmidi=", alsa_rawmidi_setup);
-#endif /* CONFIG_SND_OSSEMUL */
-#endif /* ifndef MODULE */
-
 EXPORT_SYMBOL(snd_rawmidi_output_params);
 EXPORT_SYMBOL(snd_rawmidi_input_params);
 EXPORT_SYMBOL(snd_rawmidi_drop_output);
--- diff/sound/core/rtctimer.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/rtctimer.c	2004-05-27 18:34:19.000000000 +0100
@@ -25,6 +25,7 @@
 #include <linux/time.h>
 #include <linux/threads.h>
 #include <linux/interrupt.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/timer.h>
 #include <sound/info.h>
@@ -177,21 +178,9 @@
 module_init(rtctimer_init)
 module_exit(rtctimer_exit)
 
-MODULE_PARM(rtctimer_freq, "i");
+module_param(rtctimer_freq, int, 0444);
 MODULE_PARM_DESC(rtctimer_freq, "timer frequency in Hz");
 
 MODULE_LICENSE("GPL");
 
-#ifndef MODULE
-/* format is: snd-rtctimer=freq */
-
-static int __init rtctimer_setup(char *str)
-{
-	(void)(get_option(&str,&rtctimer_freq) == 2);
-	return 1;
-}
-
-__setup("snd-rtctimer=", rtctimer_setup);
-#endif /* ifndef MODULE */
-
 #endif /* CONFIG_RTC || CONFIG_RTC_MODULE */
--- diff/sound/core/seq/Makefile	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/Makefile	2004-05-27 18:34:19.000000000 +0100
@@ -51,7 +51,6 @@
 obj-$(call sequencer,$(CONFIG_SND_CS4231)) += $(RAWMIDI_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_CS4232)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_CS4236)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
-obj-$(call sequencer,$(CONFIG_SND_PC98_CS4232)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_ES1688)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_GUSCLASSIC)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_GUSMAX)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
--- diff/sound/core/seq/instr/Makefile	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/instr/Makefile	2004-05-27 18:34:19.000000000 +0100
@@ -26,7 +26,6 @@
 obj-$(call sequencer,$(CONFIG_SND_AD1816A)) += snd-ainstr-fm.o
 obj-$(call sequencer,$(CONFIG_SND_CS4232)) += snd-ainstr-fm.o
 obj-$(call sequencer,$(CONFIG_SND_CS4236)) += snd-ainstr-fm.o
-obj-$(call sequencer,$(CONFIG_SND_PC98_CS4232)) += snd-ainstr-fm.o
 obj-$(call sequencer,$(CONFIG_SND_ES1688)) += snd-ainstr-fm.o
 obj-$(call sequencer,$(CONFIG_SND_GUSCLASSIC)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o
 obj-$(call sequencer,$(CONFIG_SND_GUSMAX)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o
--- diff/sound/core/seq/oss/seq_oss.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/oss/seq_oss.c	2004-05-27 18:34:19.000000000 +0100
@@ -22,6 +22,7 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/initval.h>
@@ -40,7 +41,7 @@
 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
 
 #ifdef SNDRV_SEQ_OSS_DEBUG
-MODULE_PARM(seq_oss_debug, "i");
+module_param(seq_oss_debug, int, 0644);
 MODULE_PARM_DESC(seq_oss_debug, "debug option");
 int seq_oss_debug = 0;
 #endif
--- diff/sound/core/seq/oss/seq_oss_init.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/oss/seq_oss_init.c	2004-05-27 18:34:19.000000000 +0100
@@ -28,17 +28,18 @@
 #include "seq_oss_timer.h"
 #include "seq_oss_event.h"
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 
 /*
  * common variables
  */
-MODULE_PARM(maxqlen, "i");
+static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN;
+module_param(maxqlen, int, 0444);
 MODULE_PARM_DESC(maxqlen, "maximum queue length");
 
 static int system_client = -1; /* ALSA sequencer client number */
 static int system_port = -1;
 
-int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN;
 static int num_clients;
 static seq_oss_devinfo_t *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS];
 
--- diff/sound/core/seq/seq.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/seq.c	2004-05-27 18:34:19.000000000 +0100
@@ -21,6 +21,7 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 
@@ -34,7 +35,11 @@
 #include "seq_info.h"
 #include <sound/seq_device.h>
 
+#if defined(CONFIG_SND_SEQ_DUMMY_MODULE)
+int seq_client_load[64] = {[0] = SNDRV_SEQ_CLIENT_DUMMY, [1 ... 63] = -1};
+#else
 int seq_client_load[64] = {[0 ... 63] = -1};
+#endif
 int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL;
 int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE;
 int seq_default_timer_card = -1;
@@ -48,19 +53,20 @@
 MODULE_CLASSES("{sound}");
 MODULE_SUPPORTED_DEVICE("sound");
 
-MODULE_PARM(seq_client_load, "1-64i");
+static int boot_devs;
+module_param_array(seq_client_load, int, boot_devs, 0444);
 MODULE_PARM_DESC(seq_client_load, "The numbers of global (system) clients to load through kmod.");
-MODULE_PARM(seq_default_timer_class, "i");
+module_param(seq_default_timer_class, int, 0644);
 MODULE_PARM_DESC(seq_default_timer_class, "The default timer class.");
-MODULE_PARM(seq_default_timer_sclass, "i");
+module_param(seq_default_timer_sclass, int, 0644);
 MODULE_PARM_DESC(seq_default_timer_sclass, "The default timer slave class.");
-MODULE_PARM(seq_default_timer_card, "i");
+module_param(seq_default_timer_card, int, 0644);
 MODULE_PARM_DESC(seq_default_timer_card, "The default timer card number.");
-MODULE_PARM(seq_default_timer_device, "i");
+module_param(seq_default_timer_device, int, 0644);
 MODULE_PARM_DESC(seq_default_timer_device, "The default timer device number.");
-MODULE_PARM(seq_default_timer_subdevice, "i");
+module_param(seq_default_timer_subdevice, int, 0644);
 MODULE_PARM_DESC(seq_default_timer_subdevice, "The default timer subdevice number.");
-MODULE_PARM(seq_default_timer_resolution, "i");
+module_param(seq_default_timer_resolution, int, 0644);
 MODULE_PARM_DESC(seq_default_timer_resolution, "The default timer resolution in Hz.");
 
 /*
--- diff/sound/core/seq/seq_dummy.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/seq_dummy.c	2004-05-27 18:34:19.000000000 +0100
@@ -21,6 +21,7 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include "seq_clientmgr.h"
 #include <sound/initval.h>
@@ -64,12 +65,14 @@
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
 MODULE_SUPPORTED_DEVICE("sound");
-MODULE_PARM(ports, "i");
+
+static int ports = 1;
+static int duplex = 0;
+
+module_param(ports, int, 0444);
 MODULE_PARM_DESC(ports, "number of ports to be created");
-MODULE_PARM(duplex, "i");
+module_param(duplex, bool, 0444);
 MODULE_PARM_DESC(duplex, "create DUPLEX ports");
-int ports = 1;
-int duplex = 0;
 
 typedef struct snd_seq_dummy_port {
 	int client;
--- diff/sound/core/seq/seq_midi.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/seq_midi.c	2004-05-27 18:34:19.000000000 +0100
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/moduleparam.h>
 #include <asm/semaphore.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
@@ -45,10 +46,10 @@
 MODULE_CLASSES("{sound}");
 MODULE_SUPPORTED_DEVICE("sound");
 int output_buffer_size = PAGE_SIZE;
-MODULE_PARM(output_buffer_size, "i");
+module_param(output_buffer_size, int, 0644);
 MODULE_PARM_DESC(output_buffer_size, "Output buffer size in bytes.");
 int input_buffer_size = PAGE_SIZE;
-MODULE_PARM(input_buffer_size, "i");
+module_param(input_buffer_size, int, 0644);
 MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes.");
 
 /* data for this midi synth driver */
--- diff/sound/core/sound.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/sound.c	2004-05-27 18:34:19.000000000 +0100
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
@@ -45,15 +46,15 @@
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
 MODULE_SUPPORTED_DEVICE("sound");
-MODULE_PARM(major, "i");
+module_param(major, int, 0444);
 MODULE_PARM_DESC(major, "Major # for sound driver.");
 MODULE_PARM_SYNTAX(major, "default:116,skill:devel");
-MODULE_PARM(cards_limit, "i");
+module_param(cards_limit, int, 0444);
 MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards.");
 MODULE_PARM_SYNTAX(cards_limit, "default:8,skill:advanced");
 MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
 #ifdef CONFIG_DEVFS_FS
-MODULE_PARM(device_mode, "i");
+module_param(device_mode, int, 0444);
 MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs.");
 MODULE_PARM_SYNTAX(device_mode, "default:0666,base:8");
 #endif
@@ -465,6 +466,12 @@
 EXPORT_SYMBOL(snd_card_file_remove);
 #ifdef CONFIG_PM
 EXPORT_SYMBOL(snd_power_wait);
+EXPORT_SYMBOL(snd_card_set_pm_callback);
+EXPORT_SYMBOL(snd_card_set_dev_pm_callback);
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(snd_card_pci_suspend);
+EXPORT_SYMBOL(snd_card_pci_resume);
+#endif
 #endif
   /* device.c */
 EXPORT_SYMBOL(snd_device_new);
--- diff/sound/core/timer.c	2004-05-19 22:13:19.000000000 +0100
+++ source/sound/core/timer.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/timer.h>
 #include <sound/control.h>
@@ -46,7 +47,7 @@
 MODULE_DESCRIPTION("ALSA timer interface");
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
-MODULE_PARM(timer_limit, "i");
+module_param(timer_limit, int, 0444);
 MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
 
 typedef struct {
@@ -1512,7 +1513,6 @@
 
 static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params)
 {
-	unsigned long flags;
 	snd_timer_user_t *tu;
 	snd_timer_params_t params;
 	snd_timer_t *t;
@@ -1548,18 +1548,17 @@
 		goto _end;
 	}
 	snd_timer_stop(tu->timeri);
-	spin_lock_irqsave(&t->lock, flags);
-	if (params.flags & SNDRV_TIMER_PSFLG_AUTO) {
+	spin_lock_irq(&t->lock);
+	tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
+			       SNDRV_TIMER_IFLG_EXCLUSIVE|
+			       SNDRV_TIMER_IFLG_EARLY_EVENT);
+	if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
 		tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
-	} else {
-		tu->timeri->flags &= ~SNDRV_TIMER_IFLG_AUTO;
-	}
-	if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE) {
+	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.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
+		tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
+	spin_unlock_irq(&t->lock);
 	if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) {
 		if (tu->tread) {
 			ttr = (snd_timer_tread_t *)kmalloc(params.queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
@@ -1577,6 +1576,24 @@
 			}
 		}
 	}
+	tu->qhead = tu->qtail = tu->qused = 0;
+	if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
+		if (tu->tread) {
+			snd_timer_tread_t tread;
+			tread.event = SNDRV_TIMER_EVENT_EARLY;
+			tread.tstamp.tv_sec = 0;
+			tread.tstamp.tv_nsec = 0;
+			tread.val = 0;
+			snd_timer_user_append_to_tqueue(tu, &tread);
+		} else {
+			snd_timer_read_t *r = &tu->queue[0];
+			r->resolution = 0;
+			r->ticks = 0;
+			tu->qused++;
+			tu->qtail++;
+		}
+		
+	}
 	tu->filter = params.filter;
 	tu->ticks = params.ticks;
 	err = 0;
@@ -1588,7 +1605,6 @@
 
 static int snd_timer_user_status(struct file *file, snd_timer_status_t *_status)
 {
-	unsigned long flags;
 	snd_timer_user_t *tu;
 	snd_timer_status_t status;
 	
@@ -1599,9 +1615,9 @@
 	status.resolution = snd_timer_resolution(tu->timeri);
 	status.lost = tu->timeri->lost;
 	status.overrun = tu->overrun;
-	spin_lock_irqsave(&tu->qlock, flags);
+	spin_lock_irq(&tu->qlock);
 	status.queue = tu->qused;
-	spin_unlock_irqrestore(&tu->qlock, flags);
+	spin_unlock_irq(&tu->qlock);
 	if (copy_to_user(_status, &status, sizeof(status)))
 		return -EFAULT;
 	return 0;
@@ -1848,18 +1864,6 @@
 module_init(alsa_timer_init)
 module_exit(alsa_timer_exit)
 
-#ifndef MODULE
-/* format is: snd-timer=timer_limit */
-
-static int __init alsa_timer_setup(char *str)
-{
-	(void)(get_option(&str,&timer_limit) == 2);
-	return 1;
-}
-
-__setup("snd-timer=", alsa_timer_setup);
-#endif /* ifndef MODULE */
-
 EXPORT_SYMBOL(snd_timer_open);
 EXPORT_SYMBOL(snd_timer_close);
 EXPORT_SYMBOL(snd_timer_resolution);
--- diff/sound/drivers/dummy.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/dummy.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,11 +24,11 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -129,23 +129,24 @@
 static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
 //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for dummy soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(pcm_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_devs, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
 MODULE_PARM_SYNTAX(pcm_devs, SNDRV_ENABLED ",allows:{{0,4}},default:1,dialog:list");
-MODULE_PARM(pcm_substreams, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_substreams, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver.");
 MODULE_PARM_SYNTAX(pcm_substreams, SNDRV_ENABLED ",allows:{{1,16}},default:8,dialog:list");
-//MODULE_PARM(midi_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+//module_param_array(midi_devs, int, boot_devs, 0444);
 //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");
 //MODULE_PARM_SYNTAX(midi_devs, SNDRV_ENABLED ",allows:{{0,2}},default:8,dialog:list");
 
@@ -661,27 +662,3 @@
 
 module_init(alsa_card_dummy_init)
 module_exit(alsa_card_dummy_exit)
-
-#ifndef MODULE
-
-/* format is: snd-dummy=enable,index,id,
-			pcm_devs,pcm_substreams */
-
-static int __init alsa_card_dummy_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 &&
-	       get_option(&str,&pcm_devs[nr_dev]) == 2 &&
-	       get_option(&str,&pcm_substreams[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-dummy=", alsa_card_dummy_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/drivers/mpu401/mpu401.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/mpu401/mpu401.c	2004-05-27 18:34:19.000000000 +0100
@@ -30,9 +30,9 @@
 #ifdef CONFIG_ACPI_BUS
 #include <acpi/acpi_bus.h>
 #endif
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #ifdef CONFIG_ACPI_BUS
@@ -52,35 +52,28 @@
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* MPU-401 port number */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* MPU-401 IRQ */
-#ifdef CONFIG_X86_PC9800
-static int pc98ii[SNDRV_CARDS];				/* PC98-II dauther board */
-#endif
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for MPU-401 device.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for MPU-401 device.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable MPU-401 device.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 #ifdef USE_ACPI_PNP
-MODULE_PARM(acpipnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(acpipnp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(acpipnp, "ACPI PnP detection for MPU-401 device.");
 MODULE_PARM_SYNTAX(acpipnp, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
 #endif
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for MPU-401 device.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-#ifdef CONFIG_X86_PC9800
-MODULE_PARM(pc98ii, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(pc98ii, "Roland MPU-PC98II support.");
-MODULE_PARM_SYNTAX(pc98ii, SNDRV_BOOLEAN_FALSE_DESC);
-#endif
 
 #ifndef CONFIG_ACPI_BUS
 struct acpi_device;
@@ -187,9 +180,6 @@
 	}
 #endif
 	if (snd_mpu401_uart_new(card, 0,
-#ifdef CONFIG_X86_PC9800
-				pc98ii[dev] ? MPU401_HW_PC98II :
-#endif
 				MPU401_HW_MPU401,
 				port[dev], 0,
 				irq[dev], irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) {
@@ -303,35 +293,3 @@
 
 module_init(alsa_card_mpu401_init)
 module_exit(alsa_card_mpu401_exit)
-
-#ifndef MODULE
-
-/* format is: snd-mpu401=enable,index,id,acpipnp[,pc98ii],port,irq */
-
-static int __init alsa_card_mpu401_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-
-	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 &&
-	       get_option(&str,&pnp) == 2 &&
-#ifdef CONFIG_X86_PC9800
-	       get_option(&str,&pc98ii[nr_dev]) == 2 &&
-#endif
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2);
-#ifdef USE_ACPI_PNP
-	if (pnp != INT_MAX)
-		acpipnp[nr_dev] = pnp;
-#endif
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-mpu401=", alsa_card_mpu401_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/drivers/mtpav.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/mtpav.c	2004-05-27 18:34:19.000000000 +0100
@@ -55,8 +55,8 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
 #include <linux/delay.h>
@@ -83,19 +83,19 @@
 static int irq = MTPAV_IRQ;		/* 7, 5 */
 static int hwports = MTPAV_MAX_PORTS;	/* use hardware ports 1-8 */
 
-MODULE_PARM(index, "i");
+module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for MotuMTPAV MIDI.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "s");
+module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for MotuMTPAV MIDI.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(port, "l");
+module_param(port, long, 0444);
 MODULE_PARM_DESC(port, "Parallel port # for MotuMTPAV MIDI.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x378},{0x278}},dialog:list");
-MODULE_PARM(irq, "i");
+module_param(irq, int, 0444);
 MODULE_PARM_DESC(irq, "Parallel IRQ # for MotuMTPAV MIDI.");
 MODULE_PARM_SYNTAX(irq,  SNDRV_ENABLED ",allows:{{7},{5}},dialog:list");
-MODULE_PARM(hwports, "i");
+module_param(hwports, int, 0444);
 MODULE_PARM_DESC(hwports, "Hardware ports # for MotuMTPAV MIDI.");
 MODULE_PARM_SYNTAX(hwports, SNDRV_ENABLED ",allows:{{1,8}},dialog:list");
 
@@ -800,25 +800,3 @@
 
 module_init(alsa_card_mtpav_init)
 module_exit(alsa_card_mtpav_exit)
-
-#ifndef MODULE
-
-/* format is: snd-mtpav=enable,index,id,
-			port,irq,hwports */
-
-static int __init alsa_card_mtpav_setup(char *str)
-{
-        int __attribute__ ((__unused__)) enable = 1;
-
-	(void)(get_option(&str,&enable) == 2 &&
-	       get_option(&str,&index) == 2 &&
-	       get_id(&str,&id) == 2 &&
-	       get_option_long(&str,&port) == 2 &&
-	       get_option(&str,&irq) == 2 &&
-	       get_option(&str,&hwports) == 2);
-	return 1;
-}
-
-__setup("snd-mtpav=", alsa_card_mtpav_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/drivers/opl3/opl3_lib.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/opl3/opl3_lib.c	2004-05-27 18:34:19.000000000 +0100
@@ -416,26 +416,6 @@
 	case OPL3_HW_OPL3_FM801:
 		opl3->command = &snd_opl3_command;
 		break;
-	case OPL3_HW_OPL3_PC98:
-		opl3->command = &snd_opl3_command;
-
-		/* Initialize? */
-		opl3->command(opl3, OPL3_RIGHT | 0x05, 0x05);
-		opl3->command(opl3, OPL3_RIGHT | 0x08, 0x04);
-		opl3->command(opl3, OPL3_RIGHT | 0x08, 0x00);
-		opl3->command(opl3, OPL3_LEFT | 0xf7, 0x00);
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x60);
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x80);
-		inb(opl3->l_port);
-		
-		opl3->command(opl3, OPL3_LEFT | 0x02, 0xff);
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x21);
-		inb(opl3->l_port);
-		
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x60);
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x80);
-
-		break;
 	case OPL3_HW_OPL3_CS4281:
 		opl3->command = &snd_opl3_cs4281_command;
 		break;
--- diff/sound/drivers/opl3/opl3_seq.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/opl3/opl3_seq.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,6 +24,7 @@
 
 #include "opl3_voice.h"
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
@@ -32,7 +33,7 @@
 MODULE_CLASSES("{sound}");
 
 int use_internal_drums = 0;
-MODULE_PARM(use_internal_drums, "i");
+module_param(use_internal_drums, bool, 0444);
 MODULE_PARM_DESC(use_internal_drums, "Enable internal OPL2/3 drums.");
 
 int snd_opl3_synth_use_inc(opl3_t * opl3)
--- diff/sound/drivers/opl4/opl4_seq.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/opl4/opl4_seq.c	2004-05-27 18:34:19.000000000 +0100
@@ -33,6 +33,7 @@
 
 #include "opl4_local.h"
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
@@ -42,7 +43,7 @@
 
 int volume_boost = 8;
 
-MODULE_PARM(volume_boost, "i");
+module_param(volume_boost, int, 0644);
 MODULE_PARM_DESC(volume_boost, "Additional volume for OPL4 wavetable sounds.");
 MODULE_PARM_SYNTAX(volume_boost, "default:8");
 
--- diff/sound/drivers/serial-u16550.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/serial-u16550.c	2004-05-27 18:34:19.000000000 +0100
@@ -35,9 +35,9 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <linux/serial_reg.h>
@@ -77,39 +77,40 @@
 static int ins[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};	/* 1 to 16 */
 static int adaptor[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = SNDRV_SERIAL_SOUNDCANVAS};
 static int droponfull[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS -1)] = SNDRV_SERIAL_NORMALBUFF };
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Serial MIDI.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Serial MIDI.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable UART16550A chip.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for UART16550A chip.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for UART16550A chip.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(speed, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(speed, int, boot_devs, 0444);
 MODULE_PARM_DESC(speed, "Speed in bauds.");
 MODULE_PARM_SYNTAX(speed, SNDRV_ENABLED ",allows:{9600,19200,38400,57600,115200},dialog:list");
-MODULE_PARM(base, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(base, int, boot_devs, 0444);
 MODULE_PARM_DESC(base, "Base for divisor in bauds.");
 MODULE_PARM_SYNTAX(base, SNDRV_ENABLED ",allows:{57600,115200,230400,460800},dialog:list");
-MODULE_PARM(outs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(outs, int, boot_devs, 0444);
 MODULE_PARM_DESC(outs, "Number of MIDI outputs.");
-MODULE_PARM(ins, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ins, int, boot_devs, 0444);
 MODULE_PARM_DESC(ins, "Number of MIDI inputs.");
-MODULE_PARM(droponfull, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(droponfull, bool, boot_devs, 0444);
 MODULE_PARM_DESC(droponfull, "Flag to enable drop-on-full buffer mode");
 MODULE_PARM_SYNTAX(droponfull, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 
 MODULE_PARM_SYNTAX(outs, SNDRV_ENABLED ",allows:{{1,16}},dialog:list");
 MODULE_PARM_SYNTAX(ins, SNDRV_ENABLED ",allows:{{1,16}},dialog:list");
-MODULE_PARM(adaptor, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(adaptor, int, boot_devs, 0444);
 MODULE_PARM_DESC(adaptor, "Type of adaptor.");
 MODULE_PARM_SYNTAX(adaptor, SNDRV_ENABLED ",allows:{{0=Soundcanvas,1=MS-124T,2=MS-124W S/A,3=MS-124W M/B,4=Generic}},dialog:list");
 
@@ -987,34 +988,3 @@
 
 module_init(alsa_card_serial_init)
 module_exit(alsa_card_serial_exit)
-
-#ifndef MODULE
-
-/* format is: snd-serial=enable,index,id,
-			 port,irq,speed,base,outs,
- 			 ins,adaptor,droponfull */
-
-static int __init alsa_card_serial_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&speed[nr_dev]) == 2 &&
-	       get_option(&str,&base[nr_dev]) == 2 &&
-	       get_option(&str,&outs[nr_dev]) == 2 &&
-	       get_option(&str,&ins[nr_dev]) == 2 &&
-	       get_option(&str,&adaptor[nr_dev]) == 2 &&
-	       get_option(&str,&droponfull[nr_dev]) == 2 );
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-serial=", alsa_card_serial_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/drivers/virmidi.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/virmidi.c	2004-05-27 18:34:19.000000000 +0100
@@ -45,10 +45,10 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/seq_kernel.h>
 #include <sound/seq_virmidi.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 /* hack: OSS defines midi_devs, so undefine it (versioned symbols) */
@@ -66,17 +66,18 @@
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
 static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for virmidi soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for virmidi soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable this soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(midi_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(midi_devs, int, boot_devs, 0444);
 MODULE_PARM_DESC(midi_devs, "MIDI devices # (1-8)");
 MODULE_PARM_SYNTAX(midi_devs, SNDRV_ENABLED ",allows:{{1,8}}");
 
@@ -162,25 +163,3 @@
 
 module_init(alsa_card_virmidi_init)
 module_exit(alsa_card_virmidi_exit)
-
-#ifndef MODULE
-
-/* format is: snd-virmidi=enable,index,id,midi_devs */
-
-static int __init alsa_card_virmidi_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 &&
-	       get_option(&str,&midi_devs[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-virmidi=", alsa_card_virmidi_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/Kconfig	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/Kconfig	2004-05-27 18:34:19.000000000 +0100
@@ -51,16 +51,6 @@
 	  Say 'Y' or 'M' to include support for CS4235,CS4236,CS4237B,CS4238B,CS4239
 	  chips from Cirrus Logic - Crystal Semiconductors.
 
-config SND_PC98_CS4232
-	tristate "NEC PC9800 CS4232 driver"
-	depends on SND && X86_PC9800
-	select SND_OPL3_LIB
-	select SND_MPU401_UART
-	select SND_PCM
-	help
-	  Say 'Y' or 'M' to include support for NEC PC-9801/PC-9821 on-board
-	  soundchip based on CS4232.
-
 config SND_ES968
 	tristate "Generic ESS ES968 driver"
 	depends on SND && ISAPNP
--- diff/sound/isa/ad1816a/ad1816a.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/ad1816a/ad1816a.c	2004-05-27 18:34:19.000000000 +0100
@@ -23,8 +23,8 @@
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/ad1816a.h>
 #include <sound/mpu401.h>
@@ -56,35 +56,36 @@
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for ad1816a based soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for ad1816a based soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for ad1816a driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ad1816a driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for ad1816a driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for ad1816a driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for ad1816a driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
 
@@ -323,33 +324,3 @@
 
 module_init(alsa_card_ad1816a_init)
 module_exit(alsa_card_ad1816a_exit)
-
-#ifndef MODULE
-
-/* format is: snd-ad1816a=enable,index,id,port,
-			  mpu_port,fm_port,irq,mpu_irq,
-			  dma1,dma2 */
-
-static int __init alsa_card_ad1816a_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-ad1816a=", alsa_card_ad1816a_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/ad1848/ad1848.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/ad1848/ad1848.c	2004-05-27 18:34:19.000000000 +0100
@@ -25,9 +25,9 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/ad1848.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #define chip_t ad1848_t
@@ -47,26 +47,27 @@
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,11,12,15 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
 static int thinkpad[SNDRV_CARDS];			/* Thinkpad special case */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for AD1848 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for AD1848 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable AD1848 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for AD1848 driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for AD1848 driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for AD1848 driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(thinkpad, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(thinkpad, bool, boot_devs, 0444);
 MODULE_PARM_DESC(thinkpad, "Enable only for the onboard CS4248 of IBM Thinkpad 360/750/755 series.");
 MODULE_PARM_SYNTAX(thinkpad,  SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 
@@ -159,29 +160,3 @@
 
 module_init(alsa_card_ad1848_init)
 module_exit(alsa_card_ad1848_exit)
-
-#ifndef MODULE
-
-/* format is: snd-ad1848=enable,index,id,port,
-			 irq,dma1 */
-
-static int __init alsa_card_ad1848_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&thinkpad[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-ad1848=", alsa_card_ad1848_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/ad1848/ad1848_lib.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/ad1848/ad1848_lib.c	2004-05-27 18:34:19.000000000 +0100
@@ -647,12 +647,12 @@
 }
 
 #ifdef CONFIG_PM
-static void snd_ad1848_suspend(ad1848_t *chip) {
-
-	snd_card_t *card = chip->card;
+static int snd_ad1848_suspend(snd_card_t *card, unsigned int state)
+{
+	ad1848_t *chip = snd_magic_cast(ad1848_t, card->pm_private_data, return -EINVAL);
 
 	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
+		return 0;
 
 	snd_pcm_suspend_all(chip->pcm);
 	/* FIXME: save registers? */
@@ -661,14 +661,15 @@
 		snd_ad1848_thinkpad_twiddle(chip, 0);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void snd_ad1848_resume(ad1848_t *chip) {
-
-	snd_card_t *card = chip->card;
+static int snd_ad1848_resume(snd_card_t *card, unsigned int state)
+{
+	ad1848_t *chip = snd_magic_cast(ad1848_t, card->pm_private_data, return -EINVAL);
 
 	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
+		return 0;
 
 	if (chip->thinkpad_flag)
 		snd_ad1848_thinkpad_twiddle(chip, 1);
@@ -676,43 +677,8 @@
 	/* FIXME: restore registers? */
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-/* callback for control API */
-static int snd_ad1848_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	ad1848_t *chip = (ad1848_t *) card->power_state_private_data;
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		snd_ad1848_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		snd_ad1848_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int snd_ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-	ad1848_t *chip = snd_magic_cast(ad1848_t, dev->data, return 0);
-
-	switch (rqst) {
-	case PM_SUSPEND:
-		snd_ad1848_suspend(chip);
-		break;
-	case PM_RESUME:
-		snd_ad1848_resume(chip);
-		break;
-	}
 	return 0;
 }
-
 #endif /* CONFIG_PM */
 
 static int snd_ad1848_probe(ad1848_t * chip)
@@ -891,10 +857,6 @@
 
 static int snd_ad1848_free(ad1848_t *chip)
 {
-#ifdef CONFIG_PM
-        if (chip->thinkpad_pmstate)
-                pm_unregister(chip->thinkpad_pmstate);
-#endif
 	if (chip->res_port) {
 		release_resource(chip->res_port);
 		kfree_nocheck(chip->res_port);
@@ -973,14 +935,7 @@
 		chip->thinkpad_flag = 1;
 		chip->hardware = AD1848_HW_DETECT; /* reset */
 		snd_ad1848_thinkpad_twiddle(chip, 1);
-#ifdef CONFIG_PM
-		chip->thinkpad_pmstate = pm_register(PM_ISA_DEV, 0, snd_ad1848_pm_callback);
-		if (chip->thinkpad_pmstate) {
-			chip->thinkpad_pmstate->data = chip;
-			card->set_power_state = snd_ad1848_set_power_state; /* callback */
-			card->power_state_private_data = chip;
-		}
-#endif
+		snd_card_set_isa_pm_callback(card, snd_ad1848_suspend, snd_ad1848_resume, chip);
 	}
 
 	if (snd_ad1848_probe(chip) < 0) {
--- diff/sound/isa/als100.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/als100.c	2004-05-27 18:34:19.000000000 +0100
@@ -25,8 +25,8 @@
 #include <linux/wait.h>
 #include <linux/time.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
@@ -59,35 +59,36 @@
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
 static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
 static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for als100 based soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for als100 based soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable als100 based soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for als100 driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for als100 driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for als100 driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for als100 driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for als100 driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma8, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma8, "8-bit DMA # for als100 driver.");
 MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC);
-MODULE_PARM(dma16, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma16, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma16, "16-bit DMA # for als100 driver.");
 MODULE_PARM_SYNTAX(dma16, SNDRV_DMA16_DESC);
 
@@ -345,33 +346,3 @@
 
 module_init(alsa_card_als100_init)
 module_exit(alsa_card_als100_exit)
-
-#ifndef MODULE
-
-/* format is: snd-als100=enable,index,id,port,
-			 mpu_port,fm_port,irq,mpu_irq,
-			 dma8,dma16 */
-
-static int __init alsa_card_als100_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma8[nr_dev]) == 2 &&
-	       get_option(&str,&dma16[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-als100=", alsa_card_als100_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/azt2320.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/azt2320.c	2004-05-27 18:34:19.000000000 +0100
@@ -36,8 +36,8 @@
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/cs4231.h>
 #include <sound/mpu401.h>
@@ -68,38 +68,39 @@
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for azt2320 driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(wss_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(wss_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver.");
 MODULE_PARM_SYNTAX(wss_port, SNDRV_PORT12_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
 
@@ -378,33 +379,3 @@
 
 module_init(alsa_card_azt2320_init)
 module_exit(alsa_card_azt2320_exit)
-
-#ifndef MODULE
-
-/* format is: snd-azt2320=enable,index,id,port,
-			  wss_port,mpu_port,fm_port,
-			  irq,mpu_irq,dma1,dma2 */
-
-static int __init alsa_card_azt2320_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&wss_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-azt2320=", alsa_card_azt2320_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/cmi8330.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/cmi8330.c	2004-05-27 18:34:19.000000000 +0100
@@ -47,10 +47,10 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/ad1848.h>
 #include <sound/sb.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 /*
@@ -79,42 +79,43 @@
 static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 static int wssirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
 static int wssdma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string  for CMI8330 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable CMI8330 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 #ifdef CONFIG_PNP
-MODULE_PARM(isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(isapnp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
 MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
 #endif
 
-MODULE_PARM(sbport, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(sbport, long, boot_devs, 0444);
 MODULE_PARM_DESC(sbport, "Port # for CMI8330 SB driver.");
 MODULE_PARM_SYNTAX(sbport, SNDRV_ENABLED ",allows:{{0x220,0x280,0x20}},prefers:{0x220},base:16,dialog:list");
-MODULE_PARM(sbirq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(sbirq, int, boot_devs, 0444);
 MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330 SB driver.");
 MODULE_PARM_SYNTAX(sbirq, SNDRV_ENABLED ",allows:{{5},{7},{9},{10},{11},{12}},prefers:{5},dialog:list");
-MODULE_PARM(sbdma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(sbdma8, int, boot_devs, 0444);
 MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330 SB driver.");
 MODULE_PARM_SYNTAX(sbdma8, SNDRV_DMA8_DESC ",prefers:{1}");
-MODULE_PARM(sbdma16, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(sbdma16, int, boot_devs, 0444);
 MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330 SB driver.");
 MODULE_PARM_SYNTAX(sbdma16, SNDRV_ENABLED ",allows:{{5},{7}},prefers:{5},dialog:list");
 
-MODULE_PARM(wssport, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(wssport, long, boot_devs, 0444);
 MODULE_PARM_DESC(wssport, "Port # for CMI8330 WSS driver.");
 MODULE_PARM_SYNTAX(wssport, SNDRV_ENABLED ",allows:{{0x530},{0xe80,0xf40,0xc0}},prefers:{0x530},base:16,dialog:list");
-MODULE_PARM(wssirq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(wssirq, int, boot_devs, 0444);
 MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver.");
 MODULE_PARM_SYNTAX(wssirq, SNDRV_ENABLED ",allows:{{5},{7},{9},{10},{11},{12}},prefers:{11},dialog:list");
-MODULE_PARM(wssdma, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(wssdma, int, boot_devs, 0444);
 MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver.");
 MODULE_PARM_SYNTAX(wssdma, SNDRV_DMA8_DESC ",prefers:{0}");
 
@@ -643,41 +644,3 @@
 
 module_init(alsa_card_cmi8330_init)
 module_exit(alsa_card_cmi8330_exit)
-
-#ifndef MODULE
-
-/* format is: snd-cmi8330=enable,index,id,isapnp,
-			  sbport,sbirq,
-			  sbdma8,sbdma16,
-			  wssport,wssirq,
-			  wssdma */
-
-static int __init alsa_card_cmi8330_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-
-	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 &&
-	       get_option(&str,&pnp) == 2 &&
-	       get_option_long(&str,&sbport[nr_dev]) == 2 &&
-	       get_option(&str,&sbirq[nr_dev]) == 2 &&
-	       get_option(&str,&sbdma8[nr_dev]) == 2 &&
-	       get_option(&str,&sbdma16[nr_dev]) == 2 &&
-	       get_option_long(&str,&wssport[nr_dev]) == 2 &&
-	       get_option(&str,&wssirq[nr_dev]) == 2 &&
-	       get_option(&str,&wssdma[nr_dev]) == 2);
-#ifdef CONFIG_PNP
-	if (pnp != INT_MAX)
-		isapnp[nr_dev] = pnp;
-#endif
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-cmi8330=", alsa_card_cmi8330_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/cs423x/Makefile	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/cs423x/Makefile	2004-05-27 18:34:19.000000000 +0100
@@ -8,7 +8,6 @@
 snd-cs4231-objs := cs4231.o
 snd-cs4232-objs := cs4232.o
 snd-cs4236-objs := cs4236.o
-snd-pc98-cs4232-objs := pc98.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AZT2320) += snd-cs4231-lib.o
@@ -22,6 +21,5 @@
 obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-cs4231-lib.o
 obj-$(CONFIG_SND_WAVEFRONT) += snd-cs4231-lib.o
 obj-$(CONFIG_SND_SSCAPE) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_PC98_CS4232) += snd-pc98-cs4232.o snd-cs4231-lib.o
 
 obj-m := $(sort $(obj-m))
--- diff/sound/isa/cs423x/cs4231.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/cs423x/cs4231.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,10 +24,10 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/cs4231.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #define chip_t cs4231_t
@@ -47,32 +47,33 @@
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 9,11,12,15 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for CS4231 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for CS4231 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable CS4231 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for CS4231 driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for CS4231 driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for CS4231 driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for CS4231 driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for CS4231 driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for CS4231 driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
 
@@ -179,34 +180,3 @@
 
 module_init(alsa_card_cs4231_init)
 module_exit(alsa_card_cs4231_exit)
-
-#ifndef MODULE
-
-/* format is: snd-cs4231=enable,index,id,
-			 port,mpu_port,irq,mpu_irq,
-			 dma1,dma2 */
-
-static int __init alsa_card_cs4231_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-
-	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 &&
-	       get_option(&str,&pnp) == 2 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-cs4231=", alsa_card_cs4231_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/cs423x/cs4231_lib.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/cs423x/cs4231_lib.c	2004-05-27 18:34:19.000000000 +0100
@@ -979,19 +979,27 @@
 	}		
 	if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
 		if (status & CS4231_PLAYBACK_IRQ) {
-			if (chip->mode & CS4231_MODE_PLAY)
-				snd_pcm_period_elapsed(chip->playback_substream);
+			if (chip->mode & CS4231_MODE_PLAY) {
+				if (chip->playback_substream)
+					snd_pcm_period_elapsed(chip->playback_substream);
+			}
 			if (chip->mode & CS4231_MODE_RECORD) {
-				snd_cs4231_overrange(chip);
-				snd_pcm_period_elapsed(chip->capture_substream);
+				if (chip->capture_substream) {
+					snd_cs4231_overrange(chip);
+					snd_pcm_period_elapsed(chip->capture_substream);
+				}
 			}
 		}
 	} else {
-		if (status & CS4231_PLAYBACK_IRQ)
-			snd_pcm_period_elapsed(chip->playback_substream);
+		if (status & CS4231_PLAYBACK_IRQ) {
+			if (chip->playback_substream)
+				snd_pcm_period_elapsed(chip->playback_substream);
+		}
 		if (status & CS4231_RECORD_IRQ) {
-			snd_cs4231_overrange(chip);
-			snd_pcm_period_elapsed(chip->capture_substream);
+			if (chip->capture_substream) {
+				snd_cs4231_overrange(chip);
+				snd_pcm_period_elapsed(chip->capture_substream);
+			}
 		}
 	}
 
@@ -1343,6 +1351,7 @@
 
 #ifdef CONFIG_PM
 
+/* lowlevel suspend callback for CS4231 */
 static void snd_cs4231_suspend(cs4231_t *chip)
 {
 	int reg;
@@ -1354,6 +1363,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
+/* lowlevel resume callback for CS4231 */
 static void snd_cs4231_resume(cs4231_t *chip)
 {
 	int reg;
@@ -1395,25 +1405,25 @@
 #endif
 }
 
-static int snd_cs4231_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+static int snd_cs4231_pm_suspend(snd_card_t *card, unsigned int state)
 {
-	cs4231_t *chip = snd_magic_cast(cs4231_t, dev->data, return 0);
-
-	switch (rqst) {
-	case PM_SUSPEND:
-		if (chip->suspend) {
-			snd_pcm_suspend_all(chip->pcm);
-			(*chip->suspend)(chip);
-		}
-		break;
-	case PM_RESUME:
-		if (chip->resume)
-			(*chip->resume)(chip);
-		break;
+	cs4231_t *chip = snd_magic_cast(cs4231_t, card->pm_private_data, return -EINVAL);
+	if (chip->suspend) {
+		chip->suspend(chip);
+		snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	}
 	return 0;
 }
 
+static int snd_cs4231_pm_resume(snd_card_t *card, unsigned int state)
+{
+	cs4231_t *chip = snd_magic_cast(cs4231_t, card->pm_private_data, return -EINVAL);
+	if (chip->resume) {
+		chip->resume(chip);
+		snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	}
+	return 0;
+}
 #endif /* CONFIG_PM */
 
 #ifdef LEGACY_SUPPORT
@@ -1441,10 +1451,6 @@
 		snd_dma_disable(chip->dma2);
 		free_dma(chip->dma2);
 	}
-#ifdef CONFIG_PM
-	if (chip->pm_dev)
-		pm_unregister(chip->pm_dev);
-#endif
 	if (chip->timer)
 		snd_device_free(chip->card, chip->timer);
 	snd_magic_kfree(chip);
@@ -1587,9 +1593,7 @@
 	/* Power Management */
 	chip->suspend = snd_cs4231_suspend;
 	chip->resume = snd_cs4231_resume;
-	chip->pm_dev = pm_register(PM_ISA_DEV, 0, snd_cs4231_pm_callback);
-	if (chip->pm_dev)
-		chip->pm_dev->data = chip;
+	snd_card_set_isa_pm_callback(card, snd_cs4231_pm_suspend, snd_cs4231_pm_resume, chip);
 #endif
 
 	*rchip = chip;
@@ -1659,7 +1663,7 @@
 #else
 #  ifdef EBUS_SUPPORT
         if (chip->ebus_flag) {
-                snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_PCI,
+                snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                 				      chip->dev_u.pdev,
 						      64*1024, 128*1024);
         } else {
--- diff/sound/isa/cs423x/cs4236.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/cs423x/cs4236.c	2004-05-27 18:34:19.000000000 +0100
@@ -23,11 +23,11 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/cs4231.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #define chip_t cs4231_t
@@ -95,46 +95,47 @@
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 9,11,12,15 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for " IDENT " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for " IDENT " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable " IDENT " soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 #ifdef CONFIG_PNP
-MODULE_PARM(isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(isapnp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
 MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
 #endif
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(cport, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(cport, long, boot_devs, 0444);
 MODULE_PARM_DESC(cport, "Control port # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(cport, SNDRV_PORT12_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(sb_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(sb_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(sb_port, "SB port # for " IDENT " driver (optional).");
 MODULE_PARM_SYNTAX(sb_port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
 
@@ -198,6 +199,8 @@
 	{ .id = "CSC0225", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
 	/* Intel Marlin Spike Motherboard (#2) - CS4235 */
 	{ .id = "CSC0225", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC0103" } } },
+	/* Unknown Intel mainboard - CS4235 */
+	{ .id = "CSC0225", .devs = { { "CSC0100" }, { "CSC0110" } } },
 	/* Genius Sound Maker 3DJ - CS4237B */
 	{ .id = "CSC0437", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
 	/* Digital PC 5000 Onboard - CS4236B */
@@ -618,48 +621,3 @@
 
 module_init(alsa_card_cs423x_init)
 module_exit(alsa_card_cs423x_exit)
-
-#ifndef MODULE
-
-/* format is: snd-cs4232=enable,index,id,isapnp,port,
-			 cport,mpu_port,fm_port,sb_port,
-			 irq,mpu_irq,dma1,dma2 */
-/* format is: snd-cs4236=enable,index,id,isapnp,port,
-			 cport,mpu_port,fm_port,sb_port,
-			 irq,mpu_irq,dma1,dma2 */
-
-static int __init alsa_card_cs423x_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-
-	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 &&
-	       get_option(&str,&pnp) == 2 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&cport[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&sb_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2);
-#ifdef CONFIG_PNP
-	if (pnp != INT_MAX)
-		isapnp[nr_dev] = pnp;
-#endif
-	nr_dev++;
-	return 1;
-}
-
-#ifdef CS4232
-__setup("snd-cs4232=", alsa_card_cs423x_setup);
-#else /* CS4236 */
-__setup("snd-cs4236=", alsa_card_cs423x_setup);
-#endif
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/cs423x/pc98.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/cs423x/pc98.c	2004-05-27 18:34:19.000000000 +0100
@@ -25,11 +25,11 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/cs4231.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include "sound_pc9800.h"
 
@@ -57,43 +57,44 @@
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
 static int pc98ii[SNDRV_CARDS];				/* PC98II */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for " IDENT " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for " IDENT " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable " IDENT " soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
 #if 0 /* NOT USED */
-MODULE_PARM(cport, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(cport, long, boot_devs, 0444);
 MODULE_PARM_DESC(cport, "Control port # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(cport, SNDRV_PORT12_DESC);
 #endif
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
-MODULE_PARM(pc98ii, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pc98ii, bool, boot_devs, 0444);
 MODULE_PARM_DESC(pc98ii, "Roland MPU-PC98II support.");
 MODULE_PARM_SYNTAX(pc98ii, SNDRV_BOOLEAN_FALSE_DESC);
 
@@ -435,34 +436,3 @@
 
 module_init(alsa_card_pc98_init)
 module_exit(alsa_card_pc98_exit)
-
-#ifndef MODULE
-
-/* format is: snd-pc98-cs4232=enable,index,id,port,
-			 mpu_port,fm_port,
-			 irq,mpu_irq,dma1,dma2,pc98ii */
-
-static int __init alsa_card_pc98_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2 &&
-	       get_option(&str,&pc98ii[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-pc98-cs4232=", alsa_card_pc98_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/dt019x.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/dt019x.c	2004-05-27 18:34:19.000000000 +0100
@@ -26,8 +26,8 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
@@ -53,32 +53,33 @@
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
 static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for dt019x driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for dt019x driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for dt019x driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for dt019x driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for dt019x driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma8, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma8, "8-bit DMA # for dt019x driver.");
 MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC);
 
@@ -337,32 +338,3 @@
 
 module_init(alsa_card_dt019x_init)
 module_exit(alsa_card_dt019x_exit)
-
-#ifndef MODULE
-
-/* format is: snd-dt019x=enable,index,id,
-			  port,mpu_port,fm_port,
-			  irq,mpu_irq,dma8,dma8_size */
-
-static int __init alsa_card_dt019x_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma8[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-dt019x=", alsa_card_dt019x_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/es1688/es1688.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/es1688/es1688.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/es1688.h>
 #include <sound/mpu401.h>
@@ -31,7 +32,6 @@
 #define SNDRV_LEGACY_AUTO_PROBE
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -51,29 +51,30 @@
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
 static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for ESx688 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for ESx688 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable ESx688 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for ESx688 driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ESx688 driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for ESx688 driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for ESx688 driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma8, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma8, "8-bit DMA # for ESx688 driver.");
 MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC);
 
@@ -211,32 +212,3 @@
 
 module_init(alsa_card_es1688_init)
 module_exit(alsa_card_es1688_exit)
-
-#ifndef MODULE
-
-/* format is: snd-es1688=enable,index,id,
-			 port,mpu_port,
-			 irq,mpu_irq,
-			 dma8 */
-
-static int __init alsa_card_es1688_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma8[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-es1688=", alsa_card_es1688_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/es18xx.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/es18xx.c	2004-05-27 18:34:19.000000000 +0100
@@ -72,6 +72,7 @@
 #include <linux/slab.h>
 #include <linux/pnp.h>
 #include <linux/isapnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -81,7 +82,6 @@
 #define SNDRV_LEGACY_AUTO_PROBE
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #define PFX "es18xx: "
@@ -124,7 +124,6 @@
 	spinlock_t mixer_lock;
 	spinlock_t ctrl_lock;
 #ifdef CONFIG_PM
-	struct pm_dev *pm_dev;
 	unsigned char pm_reg;
 #endif
 };
@@ -1610,12 +1609,9 @@
 
 /* Power Management support functions */
 #ifdef CONFIG_PM
-static void snd_es18xx_suspend(es18xx_t *chip)
+static int snd_es18xx_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
+	es18xx_t *chip = snd_magic_cast(es18xx_t, card->pm_private_data, return -EINVAL);
 
 	snd_pcm_suspend_all(chip->pcm);
 
@@ -1626,63 +1622,23 @@
 	snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_SUS);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void snd_es18xx_resume(es18xx_t *chip)
+static int snd_es18xx_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
+	es18xx_t *chip = snd_magic_cast(es18xx_t, card->pm_private_data, return -EINVAL);
 
 	/* restore PM register, we won't wake till (not 0x07) i/o activity though */
 	snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-/* callback for control API */
-static int snd_es18xx_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	es18xx_t *chip = (es18xx_t *) card->power_state_private_data;
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		snd_es18xx_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		snd_es18xx_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int snd_es18xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-	es18xx_t *chip = snd_magic_cast(es18xx_t, dev->data, return 0);
-
-	switch (rqst) {
-	case PM_SUSPEND:
-		snd_es18xx_suspend(chip);
-		break;
-	case PM_RESUME:
-		snd_es18xx_resume(chip);
-		break;
-	}
 	return 0;
 }
 #endif /* CONFIG_PM */
 
 static int snd_es18xx_free(es18xx_t *chip)
 {
-#ifdef CONFIG_PM
-	if (chip->pm_dev)
-		pm_unregister(chip->pm_dev);
-#endif
 	if (chip->res_port) {
 		release_resource(chip->res_port);
 		kfree_nocheck(chip->res_port);
@@ -1900,37 +1856,38 @@
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for ES18xx soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for ES18xx soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable ES18xx soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 #ifdef CONFIG_PNP
-MODULE_PARM(isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(isapnp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
 MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
 #endif
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for ES18xx driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220,0x280,0x20}},prefers:{0x220},base:16,dialog:list");
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ES18xx driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0x300,0x330,0x30},{0x800,0xffe,0x2}},prefers:{0x330,0x300},base:16,dialog:combo");
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for ES18xx driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0x388},{0x800,0xffc,0x4}},prefers:{0x388},base:16,dialog:combo");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for ES18xx driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC ",prefers:{5}");
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA 1 # for ES18xx driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA8_DESC ",prefers:{1}");
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_ENABLED ",allows:{{0},{1},{3},{5}},dialog:list,prefers:{0}");
 
@@ -2149,16 +2106,9 @@
 		chip->rmidi = rmidi;
 	}
 
-#ifdef CONFIG_PM
 	/* Power Management */
-	chip->pm_dev = pm_register(PM_ISA_DEV, 0, snd_es18xx_pm_callback);
-	if (chip->pm_dev) {
-		chip->pm_dev->data = chip;
-		/* set control api callback */
-		card->set_power_state = snd_es18xx_set_power_state;
-		card->power_state_private_data = chip;
-	}
-#endif
+	snd_card_set_isa_pm_callback(card, snd_es18xx_suspend, snd_es18xx_resume, chip);
+
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
 		return err;
@@ -2283,39 +2233,3 @@
 
 module_init(alsa_card_es18xx_init)
 module_exit(alsa_card_es18xx_exit)
-
-
-#ifndef MODULE
-
-/* format is: snd-es18xx=enable,index,id,isapnp,
-			 port,mpu_port,fm_port,irq,
-			 dma1,dma2 */
-
-static int __init alsa_card_es18xx_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-
-	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 &&
-	       get_option(&str,&pnp) == 2 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2);
-#ifdef CONFIG_PNP
-	if (pnp != INT_MAX)
-		isapnp[nr_dev] = pnp;
-#endif
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-es18xx=", alsa_card_es18xx_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/gus/gusclassic.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/gus/gusclassic.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,12 +24,12 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/time.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/gus.h>
 #define SNDRV_LEGACY_AUTO_PROBE
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -49,35 +49,36 @@
 				/* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
 static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
 static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for GUS Classic soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for GUS Classic soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable GUS Classic soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for GUS Classic driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220,0x260,0x10}},dialog:list");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for GUS Classic driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{3},{5},{9},{11},{12},{15}},dialog:list");
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for GUS Classic driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_ENABLED ",allows:{{1},{3},{5},{6},{7}},dialog:list");
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for GUS Classic driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_ENABLED ",allows:{{1},{3},{5},{6},{7}},dialog:list");
-MODULE_PARM(joystick_dac, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick_dac, int, boot_devs, 0444);
 MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS Classic driver.");
 MODULE_PARM_SYNTAX(joystick_dac, SNDRV_ENABLED ",allows:{{0,31}}");
-MODULE_PARM(channels, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(channels, "GF1 channels for GUS Classic driver.");
 MODULE_PARM_SYNTAX(channels,  SNDRV_ENABLED ",allows:{{14,32}}");
-MODULE_PARM(pcm_channels, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Classic driver.");
 MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",allows:{{2,16}}");
 
@@ -269,35 +270,3 @@
 
 module_init(alsa_card_gusclassic_init)
 module_exit(alsa_card_gusclassic_exit)
-
-#ifndef MODULE
-
-/* format is: snd-gusclassic=enable,index,id,
-			     port,irq,
-			     dma1,dma2,
-			     joystick_dac,
-			     channels,pcm_channels */
-
-static int __init alsa_card_gusclassic_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2 &&
-	       get_option(&str,&joystick_dac[nr_dev]) == 2 &&
-	       get_option(&str,&channels[nr_dev]) == 2 &&
-	       get_option(&str,&pcm_channels[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-gusclassic=", alsa_card_gusclassic_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/gus/gusextreme.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/gus/gusextreme.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/time.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/gus.h>
 #include <sound/es1688.h>
@@ -32,7 +33,6 @@
 #define SNDRV_LEGACY_AUTO_PROBE
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -56,47 +56,48 @@
 				/* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
 static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
 static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for GUS Extreme soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for GUS Extreme soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable GUS Extreme soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220,0x260,0x20}},dialog:list");
-MODULE_PARM(gf1_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(gf1_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(gf1_port, "GF1 port # for GUS Extreme driver (optional).");
 MODULE_PARM_SYNTAX(gf1_port, SNDRV_ENABLED ",allows:{{0x210,0x270,0x10}},dialog:list");
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0x300,0x320,0x10}},dialog:list");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{5},{7},{9},{10}},dialog:list");
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_ENABLED ",allows:{{5},{7},{9},{10}},dialog:list");
-MODULE_PARM(gf1_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(gf1_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(gf1_irq, "GF1 IRQ # for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(gf1_irq, SNDRV_ENABLED ",allows:{{2},{3},{5},{9},{11},{12},{15}},dialog:list");
-MODULE_PARM(dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma8, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma8, "8-bit DMA # for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC);
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "GF1 DMA # for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(joystick_dac, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick_dac, int, boot_devs, 0444);
 MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(joystick_dac, SNDRV_ENABLED ",allows:{{0,31}}");
-MODULE_PARM(channels, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(channels, "GF1 channels for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(channels, SNDRV_ENABLED ",allows:{{14,32}}");
-MODULE_PARM(pcm_channels, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Extreme driver.");
 MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",allows:{{2,16}}");
 
@@ -387,37 +388,3 @@
 
 module_init(alsa_card_gusextreme_init)
 module_exit(alsa_card_gusextreme_exit)
-
-#ifndef MODULE
-
-/* format is: snd-gusextreme=enable,index,id,
-			     port,gf1_port,mpu_port,
-			     irq,gf1_irq,mpu_irq,
-			     dma8,dma1,
-			     joystick_dac,
-			     channels,pcm_channels */
-
-static int __init alsa_card_gusextreme_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&gf1_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&gf1_irq[nr_dev]) == 2 &&
-	       get_option(&str,&mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma8[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-gusextreme=", alsa_card_gusextreme_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/gus/gusmax.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/gus/gusmax.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,13 +24,13 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/time.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/gus.h>
 #include <sound/cs4231.h>
 #define SNDRV_LEGACY_AUTO_PROBE
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -50,35 +50,36 @@
 				/* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
 static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
 static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for GUS MAX soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for GUS MAX soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable GUS MAX soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for GUS MAX driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220},{0x230},{0x240},{0x250},{0x260}},dialog:list");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for GUS MAX driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{3},{5},{9},{11},{12},{15}},dialog:list");
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for GUS MAX driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for GUS MAX driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
-MODULE_PARM(joystick_dac, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick_dac, int, boot_devs, 0444);
 MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS MAX driver.");
 MODULE_PARM_SYNTAX(joystick_dac, SNDRV_ENABLED ",allows:{{0,31}}");
-MODULE_PARM(channels, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(channels, "Used GF1 channels for GUS MAX driver.");
 MODULE_PARM_SYNTAX(channels, SNDRV_ENABLED ",allows:{{14,32}}");
-MODULE_PARM(pcm_channels, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS MAX driver.");
 MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",allows:{{2,16}}");
 
@@ -409,35 +410,3 @@
 
 module_init(alsa_card_gusmax_init)
 module_exit(alsa_card_gusmax_exit)
-
-#ifndef MODULE
-
-/* format is: snd-gusmax=enable,index,id,
-			 port,irq,
-			 dma1,dma2,
-			 joystick_dac,
-			 channels,pcm_channels */
-
-static int __init alsa_card_gusmax_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2 &&
-	       get_option(&str,&joystick_dac[nr_dev]) == 2 &&
-	       get_option(&str,&channels[nr_dev]) == 2 &&
-	       get_option(&str,&pcm_channels[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-gusmax=", alsa_card_gusmax_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/gus/interwave.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/gus/interwave.c	2004-05-27 18:34:19.000000000 +0100
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/gus.h>
 #include <sound/cs4231.h>
@@ -37,7 +38,6 @@
 #define SNDRV_LEGACY_AUTO_PROBE
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -73,46 +73,47 @@
 static int midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
 static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
 static int effect[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for InterWave soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for InterWave soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable InterWave soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(isapnp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
 MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for InterWave driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x210,0x260,0x10}},dialog:list");
 #ifdef SNDRV_STB
-MODULE_PARM(port_tc, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port_tc, long, boot_devs, 0444);
 MODULE_PARM_DESC(port_tc, "Tone control (TEA6330T - i2c bus) port # for InterWave driver.");
 MODULE_PARM_SYNTAX(port_tc, SNDRV_ENABLED ",allows:{{0x350,0x380,0x10}},dialog:list");
 #endif
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for InterWave driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{3},{5},{9},{11},{12},{15}},dialog:list");
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for InterWave driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for InterWave driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
-MODULE_PARM(joystick_dac, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick_dac, int, boot_devs, 0444);
 MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for InterWave driver.");
 MODULE_PARM_SYNTAX(joystick_dac, SNDRV_ENABLED ",allows:{{0,31}}");
-MODULE_PARM(midi, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(midi, int, boot_devs, 0444);
 MODULE_PARM_DESC(midi, "MIDI UART enable for InterWave driver.");
 MODULE_PARM_SYNTAX(midi, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
-MODULE_PARM(pcm_channels, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for InterWave driver.");
 MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",allows:{{2,16}}");
-MODULE_PARM(effect, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(effect, int, boot_devs, 0444);
 MODULE_PARM_DESC(effect, "Effects enable for InterWave driver.");
 MODULE_PARM_SYNTAX(effect, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
 
@@ -985,49 +986,3 @@
 
 module_init(alsa_card_interwave_init)
 module_exit(alsa_card_interwave_exit)
-
-#ifndef MODULE
-
-/* format is: snd-interwave=enable,index,id,isapnp,
-			    port[,port_tc],irq,
-			    dma1,dma2,
-			    joystick_dac,midi,
-			    pcm_channels,effect */
-
-static int __init alsa_card_interwave_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-
-	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 &&
-	       get_option(&str,&pnp) == 2 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-#ifdef SNDRV_STB
-	       get_option_long(&str,&port_tc[nr_dev]) == 2 &&
-#endif
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2 &&
-	       get_option(&str,&joystick_dac[nr_dev]) == 2 &&
-	       get_option(&str,&midi[nr_dev]) == 2 &&
-	       get_option(&str,&pcm_channels[nr_dev]) == 2 &&
-	       get_option(&str,&effect[nr_dev]) == 2);
-#ifdef CONFIG_PNP
-	if (pnp != INT_MAX)
-		isapnp[nr_dev] = pnp;
-#endif
-	nr_dev++;
-	return 1;
-}
-
-#ifndef SNDRV_STB
-__setup("snd-interwave=", alsa_card_interwave_setup);
-#else
-__setup("snd-interwave-stb=", alsa_card_interwave_setup);
-#endif
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/opl3sa2.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/opl3sa2.c	2004-05-27 18:34:19.000000000 +0100
@@ -25,11 +25,11 @@
 #include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/cs4231.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/io.h>
@@ -59,46 +59,47 @@
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 1,3,5,6,7 */
 static int opl3sa3_ymode[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 };   /* 0,1,2,3 */ /*SL Added*/
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for OPL3-SA soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for OPL3-SA soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable OPL3-SA soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 #ifdef CONFIG_PNP
-MODULE_PARM(isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(isapnp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
 MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
 #endif
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0xf86},{0x370},{0x100}},dialog:list");
-MODULE_PARM(sb_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(sb_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(sb_port, "SB port # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(sb_port, SNDRV_ENABLED ",allows:{{0x220},{0x240},{0x260}},dialog:list");
-MODULE_PARM(wss_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(wss_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(wss_port, "WSS port # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(wss_port, SNDRV_ENABLED ",allows:{{0x530},{0xe80},{0xf40},{0x604}},dialog:list");
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0x388}},dialog:list");
-MODULE_PARM(midi_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(midi_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(midi_port, "MIDI port # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(midi_port, SNDRV_ENABLED ",allows:{{0x330},{0x300}},dialog:list");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{0},{1},{3},{5},{9},{11},{12},{15}},dialog:list");
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_ENABLED ",allows:{{1},{3},{5},{6},{7}},dialog:list");
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_ENABLED ",allows:{{1},{3},{5},{6},{7}},dialog:list");
-MODULE_PARM(opl3sa3_ymode, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); /* SL Added */
+module_param_array(opl3sa3_ymode, int, boot_devs, 0444);
 MODULE_PARM_DESC(opl3sa3_ymode, "Speaker size selection for 3D Enhancement mode: Desktop/Large Notebook/Small Notebook/HiFi.");
 MODULE_PARM_SYNTAX(opl3sa3_ymode, SNDRV_ENABLED ",allows:{{0,3}},dialog:list");  /* SL Added */
 
@@ -151,7 +152,6 @@
 	snd_kcontrol_t *master_switch;
 	snd_kcontrol_t *master_volume;
 #ifdef CONFIG_PM
-	struct pm_dev *pm_dev;
 	void (*cs4231_suspend)(cs4231_t *);
 	void (*cs4231_resume)(cs4231_t *);
 #endif
@@ -168,6 +168,8 @@
 	{ .id = "YMH0030", .devs = { { "YMH0021" } } },
 	/* Yamaha OPL3-SA2 */
 	{ .id = "YMH0800", .devs = { { "YMH0021" } } },
+	/* Yamaha OPL3-SA2 */
+	{ .id = "YMH0801", .devs = { { "YMH0021" } } },
 	/* NeoMagic MagicWave 3DX */
 	{ .id = "NMX2200", .devs = { { "YMH2210" } } },
 	/* --- */
@@ -547,12 +549,9 @@
 
 /* Power Management support functions */
 #ifdef CONFIG_PM
-static void snd_opl3sa2_suspend(opl3sa2_t *chip)
+static int snd_opl3sa2_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
+	opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, card->pm_private_data, return -EINVAL);
 
 	snd_pcm_suspend_all(chip->cs4231->pcm); /* stop before saving regs */
 	chip->cs4231_suspend(chip->cs4231);
@@ -561,16 +560,14 @@
 	snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void snd_opl3sa2_resume(opl3sa2_t *chip)
+static int snd_opl3sa2_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, card->pm_private_data, return -EINVAL);
 	int i;
 
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
-
 	/* power up */
 	snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D0);
 
@@ -587,43 +584,8 @@
 	chip->cs4231_resume(chip->cs4231);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-/* callback for control API */
-static int snd_opl3sa2_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	opl3sa2_t *chip = (opl3sa2_t *) card->power_state_private_data;
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		snd_opl3sa2_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		snd_opl3sa2_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
-
-static int snd_opl3sa2_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-	opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, dev->data, return 0);
-
-	switch (rqst) {
-	case PM_SUSPEND:
-		snd_opl3sa2_suspend(chip);
-		break;
-	case PM_RESUME:
-		snd_opl3sa2_resume(chip);
-		break;
-	}
-	return 0;
-}
-
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_PNP
@@ -688,10 +650,6 @@
 
 static int snd_opl3sa2_free(opl3sa2_t *chip)
 {
-#ifdef CONFIG_PM
-	if (chip->pm_dev)
-		pm_unregister(chip->pm_dev);
-#endif
 	if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
 	if (chip->res_port) {
@@ -816,22 +774,12 @@
 			goto __error;
 	}
 #ifdef CONFIG_PM
-	/* Power Management */
-	chip->pm_dev = pm_register(PM_ISA_DEV, 0, snd_opl3sa2_pm_callback);
-	if (chip->pm_dev) {
-		chip->pm_dev->data = chip;
-		/* remember callbacks for cs4231 - they are called inside
-		 * opl3sa2 pm callback
-		 */
-		chip->cs4231_suspend = chip->cs4231->suspend;
-		chip->cs4231_resume = chip->cs4231->resume;
-		/* now clear callbacks for cs4231 */
-		chip->cs4231->suspend = NULL;
-		chip->cs4231->resume = NULL;
-		/* set control api callback */
-		card->set_power_state = snd_opl3sa2_set_power_state;
-		card->power_state_private_data = chip;
-	}
+	chip->cs4231_suspend = chip->cs4231->suspend;
+	chip->cs4231_resume = chip->cs4231->resume;
+	/* now clear callbacks for cs4231 */
+	chip->cs4231->suspend = NULL;
+	chip->cs4231->resume = NULL;
+	snd_card_set_isa_pm_callback(card, snd_opl3sa2_suspend, snd_opl3sa2_resume, chip);
 #endif
 
 	sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
@@ -932,42 +880,3 @@
 
 module_init(alsa_card_opl3sa2_init)
 module_exit(alsa_card_opl3sa2_exit)
-
-#ifndef MODULE
-
-/* format is: snd-opl3sa2=enable,index,id,isapnp,
-			  port,sb_port,wss_port,fm_port,
-			  midi_port,irq,dma1,dma2,
-			  opl3sa3_ymode */
-
-static int __init alsa_card_opl3sa2_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-
-	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 &&
-	       get_option(&str,&pnp) == 2 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&sb_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&wss_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&midi_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2 &&
-	       get_option(&str,&opl3sa3_ymode[nr_dev]) == 2);
-#ifdef CONFIG_PNP
-	if (pnp != INT_MAX)
-		isapnp[nr_dev] = pnp;
-#endif
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-opl3sa2=", alsa_card_opl3sa2_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/opti9xx/opti92x-ad1848.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/opti9xx/opti92x-ad1848.c	2004-05-27 18:34:19.000000000 +0100
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #ifdef CS4231
 #include <sound/cs4231.h>
@@ -48,7 +49,6 @@
 #endif
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
@@ -84,38 +84,38 @@
 static int dma2 = SNDRV_DEFAULT_DMA1;		/* 0,1,3 */
 #endif	/* CS4231 || OPTi93X */
 
-MODULE_PARM(index, "i");
+module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for opti9xx based soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "s");
+module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for opti9xx based soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-//MODULE_PARM(enable, "i");
+//module_param(enable, bool, 0444);
 //MODULE_PARM_DESC(enable, "Enable opti9xx soundcard.");
 //MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(isapnp, "i");
+module_param(isapnp, bool, 0444);
 MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
 MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
-MODULE_PARM(port, "l");
+module_param(port, long, 0444);
 MODULE_PARM_DESC(port, "WSS port # for opti9xx driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT_DESC);
-MODULE_PARM(mpu_port, "l");
+module_param(mpu_port, long, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for opti9xx driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT_DESC);
-MODULE_PARM(fm_port, "l");
+module_param(fm_port, long, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for opti9xx driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT_DESC);
-MODULE_PARM(irq, "i");
+module_param(irq, int, 0444);
 MODULE_PARM_DESC(irq, "WSS irq # for opti9xx driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(mpu_irq, "i");
+module_param(mpu_irq, int, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 irq # for opti9xx driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma1, "i");
+module_param(dma1, int, 0444);
 MODULE_PARM_DESC(dma1, "1st dma # for opti9xx driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
 #if defined(CS4231) || defined(OPTi93X)
-MODULE_PARM(dma2, "i");
+module_param(dma2, int, 0444);
 MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
 #endif	/* CS4231 || OPTi93X */
@@ -602,7 +602,11 @@
 #endif	/* CS4231 || OPTi93X */
 
 	spin_lock_irqsave(&chip->lock, flags);
+#ifndef OPTi93X
+	 outb(irq_bits << 3 | dma_bits, chip->wss_base);
+#else /* OPTi93X */
 	snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
+#endif /* OPTi93X */
 	spin_unlock_irqrestore(&chip->lock, flags);
 
 __skip_resources:
@@ -2253,47 +2257,3 @@
 
 module_init(alsa_card_opti9xx_init)
 module_exit(alsa_card_opti9xx_exit)
-
-#ifndef MODULE
-
-/* format is: snd-opti9xx=enable,index,id,isapnp,
-			  port,mpu_port,fm_port,
-			  irq,mpu_irq,
-			  dma1,[dma2] */
-
-static int __init alsa_card_opti9xx_setup(char *str)
-{
-	int __attribute__ ((__unused__)) enable = 1;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-
-	(void)(get_option(&str,&enable) == 2 &&
-	       get_option(&str,&index) == 2 &&
-	       get_id(&str,&id) == 2 &&
-	       get_option(&str,&pnp) == 2 &&
-	       get_option_long(&str,&port) == 2 &&
-	       get_option_long(&str,&mpu_port) == 2 &&
-	       get_option_long(&str,&fm_port) == 2 &&
-	       get_option(&str,&irq) == 2 &&
-	       get_option(&str,&mpu_irq) == 2 &&
-	       get_option(&str,&dma1) == 2
-#if defined(CS4231) || defined(OPTi93X)
-	       &&
-	       get_option(&str,&dma2) == 2
-#endif
-	       );
-#ifdef CONFIG_PNP
-	if (pnp != INT_MAX)
-		isapnp = pnp;
-#endif
-	return 1;
-}
-
-#if defined(OPTi93X)
-__setup("snd-opti93x=", alsa_card_opti9xx_setup);
-#elif defined(CS4231)
-__setup("snd-opti92x-cs4231=", alsa_card_opti9xx_setup);
-#else
-__setup("snd-opti92x-ad1848=", alsa_card_opti9xx_setup);
-#endif
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/sb/emu8000_patch.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/sb/emu8000_patch.c	2004-05-27 18:34:19.000000000 +0100
@@ -21,12 +21,12 @@
 
 #include "emu8000_local.h"
 #include <asm/uaccess.h>
+#include <linux/moduleparam.h>
 
-MODULE_PARM(emu8000_reset_addr, "i");
+static int emu8000_reset_addr = 0;
+module_param(emu8000_reset_addr, int, 0444);
 MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)");
 
-int emu8000_reset_addr = 0;
-
 
 /*
  * Open up channels.
--- diff/sound/isa/sb/es968.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/sb/es968.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,8 +24,8 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/sb.h>
 
@@ -45,23 +45,24 @@
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
 static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for es968 based soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for es968 based soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable es968 based soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for es968 driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for es968 driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma8, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma8, "8-bit DMA # for es968 driver.");
 MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC);
 
@@ -242,28 +243,3 @@
 
 module_init(alsa_card_es968_init)
 module_exit(alsa_card_es968_exit)
-
-#ifndef MODULE
-
-/* format is: snd-es968=enable,index,id,
-			port,irq,dma1 */
-
-static int __init alsa_card_es968_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma8[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-es968=", alsa_card_es968_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/sb/sb16.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/sb/sb16.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/sb.h>
 #include <sound/sb16_csp.h>
@@ -34,7 +35,6 @@
 #define SNDRV_LEGACY_AUTO_PROBE
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #define chip_t sb_t
@@ -92,54 +92,55 @@
 #ifdef SNDRV_SBAWE_EMU8000
 static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
 #endif
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for SoundBlaster 16 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for SoundBlaster 16 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable SoundBlaster 16 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 #ifdef CONFIG_PNP
-MODULE_PARM(isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(isapnp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
 MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
 #endif
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for SB16 driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220},{0x240},{0x260},{0x280}},dialog:list");
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for SB16 driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0x330},{0x300}},dialog:list");
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port # for SB16 PnP driver.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0x388},{0x38c},{0x390},{0x394}},dialog:list");
 #ifdef SNDRV_SBAWE_EMU8000
-MODULE_PARM(awe_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(awe_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(awe_port, "AWE port # for SB16 PnP driver.");
 MODULE_PARM_SYNTAX(awe_port, SNDRV_ENABLED ",allows:{{0x620},{0x640},{0x660},{0x680}},dialog:list");
 #endif
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for SB16 driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma8, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma8, "8-bit DMA # for SB16 driver.");
 MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC);
-MODULE_PARM(dma16, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma16, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma16, "16-bit DMA # for SB16 driver.");
 MODULE_PARM_SYNTAX(dma16, SNDRV_DMA16_DESC);
-MODULE_PARM(mic_agc, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mic_agc, int, boot_devs, 0444);
 MODULE_PARM_DESC(mic_agc, "Mic Auto-Gain-Control switch.");
 MODULE_PARM_SYNTAX(mic_agc, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
 #ifdef CONFIG_SND_SB16_CSP
-MODULE_PARM(csp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(csp, int, boot_devs, 0444);
 MODULE_PARM_DESC(csp, "ASP/CSP chip support.");
 MODULE_PARM_SYNTAX(csp, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
 #endif
 #ifdef SNDRV_SBAWE_EMU8000
-MODULE_PARM(seq_ports, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(seq_ports, int, boot_devs, 0444);
 MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth.");
 MODULE_PARM_SYNTAX(seq_ports, SNDRV_ENABLED ",allows:{{0,8}},skill:advanced");
 #endif
@@ -247,6 +248,8 @@
 	{ .id = "CTLXXXX" , .devs = { { "CTL0044" }, { "CTL0023" } } },
 	{ .id = "CTLXXXX" , .devs = { { "CTL0045" }, { "CTL0022" } } },
 #endif /* SNDRV_SBAWE */
+	/* Sound Blaster 16 PnP (Virtual PC 2004)*/
+	{ .id = "tBA03b0", .devs = { { "PNPb003" } } },
 	{ .id = "", }
 };
 
@@ -691,60 +694,3 @@
 
 module_init(alsa_card_sb16_init)
 module_exit(alsa_card_sb16_exit)
-
-#ifndef MODULE
-
-/* format is: snd-sb16=enable,index,id,isapnp,
-		       port,mpu_port,fm_port,
-		       irq,dma8,dma16,
-		       mic_agc,csp,
-		       [awe_port,seq_ports] */
-
-static int __init alsa_card_sb16_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-	int __attribute__ ((__unused__)) pnp = INT_MAX;
-	int __attribute__ ((__unused__)) xcsp = INT_MAX;
-
-	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 &&
-	       get_option(&str,&pnp) == 2 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma8[nr_dev]) == 2 &&
-	       get_option(&str,&dma16[nr_dev]) == 2 &&
-	       get_option(&str,&mic_agc[nr_dev]) == 2
-#ifdef CONFIG_SND_SB16_CSP
-	       &&
-	       get_option(&str,&xcsp) == 2
-#endif
-#ifdef SNDRV_SBAWE_EMU8000
-	       &&
-	       get_option_long(&str,&awe_port[nr_dev]) == 2 &&
-	       get_option(&str,&seq_ports[nr_dev]) == 2
-#endif
-	       );
-#ifdef CONFIG_PNP
-	if (pnp != INT_MAX)
-		isapnp[nr_dev] = pnp;
-#endif
-#ifdef CONFIG_SND_SB16_CSP
-	if (xcsp != INT_MAX)
-		csp[nr_dev] = xcsp;
-#endif
-	nr_dev++;
-	return 1;
-}
-
-#ifndef SNDRV_SBAWE_EMU8000
-__setup("snd-sb16=", alsa_card_sb16_setup);
-#else
-__setup("snd-sbawe=", alsa_card_sb16_setup);
-#endif
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/sb/sb8.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/sb/sb8.c	2004-05-27 18:34:19.000000000 +0100
@@ -23,11 +23,11 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/sb.h>
 #include <sound/opl3.h>
 #define SNDRV_LEGACY_AUTO_PROBE
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #define chip_t sb_t
@@ -44,23 +44,24 @@
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
 static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 1,3 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for SB8 driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for SB8 driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-MODULE_PARM(dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma8, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");
 MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC);
 
@@ -230,28 +231,3 @@
 
 module_init(alsa_card_sb8_init)
 module_exit(alsa_card_sb8_exit)
-
-#ifndef MODULE
-
-/* format is: snd-sb8=enable,index,id,
-		      port,irq,dma8 */
-
-static int __init alsa_card_sb8_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 &&
-	       get_option_long(&str,&port[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma8[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-sb8=", alsa_card_sb8_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/sgalaxy.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/sgalaxy.c	2004-05-27 18:34:19.000000000 +0100
@@ -27,13 +27,13 @@
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/irq.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/sb.h>
 #include <sound/ad1848.h>
 #include <sound/control.h>
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>");
@@ -49,23 +49,24 @@
 static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x530,0xe80,0xf40,0x604 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 7,9,10,11 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(sbport, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(sbport, long, boot_devs, 0444);
 MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
 MODULE_PARM_SYNTAX(sbport, SNDRV_ENABLED ",allows:{{0x220},{0x240}},dialog:list");
-MODULE_PARM(wssport, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(wssport, long, boot_devs, 0444);
 MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
 MODULE_PARM_SYNTAX(wssport, SNDRV_ENABLED ",allows:{{0x530},{0xe80},{0xf40},{0x604}},dialog:list");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{7},{9},{10},{11}},dialog:list");
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA8_DESC);
 
@@ -327,30 +328,3 @@
 
 module_init(alsa_card_sgalaxy_init)
 module_exit(alsa_card_sgalaxy_exit)
-
-#ifndef MODULE
-
-/* format is: snd-sgalaxy=enable,index,id,
-			  sbport,wssport,
-			  irq,dma1 */
-
-static int __init alsa_card_sgalaxy_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 &&
-	       get_option_long(&str,&sbport[nr_dev]) == 2 &&
-	       get_option_long(&str,&wssport[nr_dev]) == 2 &&
-	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-sgalaxy=", alsa_card_sgalaxy_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/sscape.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/sscape.c	2004-05-27 18:34:19.000000000 +0100
@@ -26,12 +26,12 @@
 #include <linux/delay.h>
 #include <linux/pnp.h>
 #include <linux/spinlock.h>
+#include <linux/moduleparam.h>
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
 #include <sound/cs4231.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <sound/sscape_ioctl.h>
@@ -49,28 +49,29 @@
 static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
 static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
 static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA;
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index number for SoundScape soundcard");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
 
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "Description for SoundScape card");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
 
-MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(port, long, boot_devs, 0444);
 MODULE_PARM_DESC(port, "Port # for SoundScape driver.");
 MODULE_PARM_SYNTAX(port, SNDRV_ENABLED);
 
-MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
 
-MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # for SoundScape driver.");
 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
 
-MODULE_PARM(dma, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma, "DMA # for SoundScape driver.");
 MODULE_PARM_SYNTAX(dma, SNDRV_DMA8_DESC);
   
@@ -1531,30 +1532,3 @@
 
 module_init(sscape_init);
 module_exit(sscape_exit);
-
-#ifndef MODULE
-
-/* format is: snd-sscape=index,id,port,irq,mpu_irq,dma */
-
-static int __init builtin_sscape_setup(char *str)
-{
-	static unsigned __initdata nr_dev;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-
-	(void)((get_option(&str, &index[nr_dev]) == 2) &&
-	       (get_id(&str, &id[nr_dev]) == 2) &&
-	       (get_option_long(&str, &port[nr_dev]) == 2) &&
-	       (get_option(&str, &irq[nr_dev]) == 2) &&
-	       (get_option(&str, &mpu_irq[nr_dev]) == 2) &&
-	       (get_option(&str, &dma[nr_dev]) == 2)); 
- 
-	++nr_dev;
-	return 1;
-}
-
-__setup("snd-sscape=", builtin_sscape_setup);
-
-#endif
-
--- diff/sound/isa/wavefront/wavefront.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/wavefront/wavefront.c	2004-05-27 18:34:19.000000000 +0100
@@ -24,8 +24,8 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/opl3.h>
 #include <sound/snd_wavefront.h>
@@ -52,49 +52,50 @@
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	    /* 0,1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	    /* 0,1,3,5,6,7 */
 static int use_cs4232_midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; 
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for WaveFront soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for WaveFront soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable WaveFront soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 #ifdef CONFIG_PNP
-MODULE_PARM(isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(isapnp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(isapnp, "ISA PnP detection for WaveFront soundcards.");
 MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
 #endif
-MODULE_PARM(cs4232_pcm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(cs4232_pcm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(cs4232_pcm_port, "Port # for CS4232 PCM interface.");
 MODULE_PARM_SYNTAX(cs4232_pcm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(cs4232_pcm_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(cs4232_pcm_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(cs4232_pcm_irq, "IRQ # for CS4232 PCM interface.");
 MODULE_PARM_SYNTAX(cs4232_pcm_irq, SNDRV_ENABLED ",allows:{{5},{7},{9},{11},{12},{15}},dialog:list");
-MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma1, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma1, "DMA1 # for CS4232 PCM interface.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
-MODULE_PARM(dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dma2, int, boot_devs, 0444);
 MODULE_PARM_DESC(dma2, "DMA2 # for CS4232 PCM interface.");
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
-MODULE_PARM(cs4232_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(cs4232_mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(cs4232_mpu_port, "port # for CS4232 MPU-401 interface.");
 MODULE_PARM_SYNTAX(cs4232_mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(cs4232_mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(cs4232_mpu_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(cs4232_mpu_irq, "IRQ # for CS4232 MPU-401 interface.");
 MODULE_PARM_SYNTAX(cs4232_mpu_irq, SNDRV_ENABLED ",allows:{{9},{11},{12},{15}},dialog:list");
-MODULE_PARM(ics2115_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ics2115_irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(ics2115_irq, "IRQ # for ICS2115.");
 MODULE_PARM_SYNTAX(ics2115_irq, SNDRV_ENABLED ",allows:{{9},{11},{12},{15}},dialog:list");
-MODULE_PARM(ics2115_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(ics2115_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(ics2115_port, "Port # for ICS2115.");
 MODULE_PARM_SYNTAX(ics2115_port, SNDRV_PORT12_DESC);
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port #.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(use_cs4232_midi, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(use_cs4232_midi, bool, boot_devs, 0444);
 MODULE_PARM_DESC(use_cs4232_midi, "Use CS4232 MPU-401 interface (inaccessibly located inside your computer)");
 MODULE_PARM_SYNTAX(use_cs4232_midi, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 
@@ -731,41 +732,3 @@
 
 module_init(alsa_card_wavefront_init)
 module_exit(alsa_card_wavefront_exit)
-
-#ifndef MODULE
-
-/* format is: snd-wavefront=enable,index,id,isapnp,
-			    cs4232_pcm_port,cs4232_pcm_irq,
-			    cs4232_mpu_port,cs4232_mpu_irq,
-			    ics2115_port,ics2115_irq,
-			    fm_port,
-			    dma1,dma2,
-			    use_cs4232_midi */
-
-static int __init alsa_card_wavefront_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 &&
-	       get_option(&str,&isapnp[nr_dev]) == 2 &&
-	       get_option_long(&str,&cs4232_pcm_port[nr_dev]) == 2 &&
-	       get_option(&str,&cs4232_pcm_irq[nr_dev]) == 2 &&
-	       get_option_long(&str,&cs4232_mpu_port[nr_dev]) == 2 &&
-	       get_option(&str,&cs4232_mpu_irq[nr_dev]) == 2 &&
-	       get_option_long(&str,&ics2115_port[nr_dev]) == 2 &&
-	       get_option(&str,&ics2115_irq[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2 &&
-	       get_option(&str,&dma2[nr_dev]) == 2 &&
-	       get_option(&str,&use_cs4232_midi[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-wavefront=", alsa_card_wavefront_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/isa/wavefront/wavefront_synth.c	2004-05-19 22:13:21.000000000 +0100
+++ source/sound/isa/wavefront/wavefront_synth.c	2004-05-27 18:34:19.000000000 +0100
@@ -27,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/snd_wavefront.h>
 #include <sound/initval.h>
@@ -83,25 +84,25 @@
 int osrun_time = 10;       /* time in seconds we wait for the OS to
 			      start running.
 			   */
-MODULE_PARM(wf_raw,"i");
+module_param(wf_raw, int, 0444);
 MODULE_PARM_DESC(wf_raw, "if non-zero, assume that we need to boot the OS");
-MODULE_PARM(fx_raw,"i");
+module_param(fx_raw, int, 0444);
 MODULE_PARM_DESC(fx_raw, "if non-zero, assume that the FX process needs help");
-MODULE_PARM(debug_default,"i");
+module_param(debug_default, int, 0444);
 MODULE_PARM_DESC(debug_default, "debug parameters for card initialization");
-MODULE_PARM(wait_usecs,"i");
+module_param(wait_usecs, int, 0444);
 MODULE_PARM_DESC(wait_usecs, "how long to wait without sleeping, usecs");
-MODULE_PARM(sleep_interval,"i");
+module_param(sleep_interval, int, 0444);
 MODULE_PARM_DESC(sleep_interval, "how long to sleep when waiting for reply");
-MODULE_PARM(sleep_tries,"i");
+module_param(sleep_tries, int, 0444);
 MODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait");
-MODULE_PARM(ospath,"s");
+module_param(ospath, charp, 0444);
 MODULE_PARM_DESC(ospath, "full pathname to processed ICS2115 OS firmware");
-MODULE_PARM(reset_time,"i");
+module_param(reset_time, int, 0444);
 MODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect");
-MODULE_PARM(ramcheck_time,"i");
+module_param(ramcheck_time, int, 0444);
 MODULE_PARM_DESC(ramcheck_time, "how many seconds to wait for the RAM test");
-MODULE_PARM(osrun_time,"i");
+module_param(osrun_time, int, 0444);
 MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS");
 
 /* if WF_DEBUG not defined, no run-time debugging messages will
--- diff/sound/oss/dmasound/dmasound_atari.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/oss/dmasound/dmasound_atari.c	2004-05-27 18:34:19.000000000 +0100
@@ -22,7 +22,6 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 
-#include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/atariints.h>
 #include <asm/atari_stram.h>
--- diff/sound/oss/nm256_audio.c	2004-05-19 22:13:23.000000000 +0100
+++ source/sound/oss/nm256_audio.c	2004-05-27 18:34:19.000000000 +0100
@@ -52,6 +52,7 @@
 /* These belong in linux/pci.h. */
 #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
+#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016
 
 /* List of cards.  */
 static struct nm256_info *nmcard_list;
@@ -1275,6 +1276,8 @@
 	return nm256_install(pcidev, REV_NM256AV, "256AV");
     if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO)
 	return nm256_install(pcidev, REV_NM256ZX, "256ZX");
+    if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO)
+	return nm256_install(pcidev, REV_NM256ZX, "256XL+");
     return -1; /* should not come here ... */
 }
 
@@ -1662,6 +1665,8 @@
 	PCI_ANY_ID, PCI_ANY_ID, 0, 0},
 	{PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO,
 	PCI_ANY_ID, PCI_ANY_ID, 0, 0},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO,
+	PCI_ANY_ID, PCI_ANY_ID, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, nm256_pci_tbl);
--- diff/sound/oss/sb_card.c	2004-05-19 22:13:23.000000000 +0100
+++ source/sound/oss/sb_card.c	2004-05-27 18:34:19.000000000 +0100
@@ -181,6 +181,13 @@
 		scc->mpucnf.io_base = pnp_port_start(dev,1);
 		return;
 	}
+	if(!strncmp("tBA",scc->card_id,3)) {
+		scc->conf.io_base   = pnp_port_start(dev,0);
+		scc->conf.irq       = pnp_irq(dev,0);
+		scc->conf.dma       = pnp_dma(dev,0);
+		scc->conf.dma2      = pnp_dma(dev,1);
+		return;
+	}
 	if(!strncmp("ESS",scc->card_id,3)) {
 		scc->conf.io_base   = pnp_port_start(dev,0);
 		scc->conf.irq       = pnp_irq(dev,0);
--- diff/sound/oss/sb_card.h	2004-05-19 22:13:23.000000000 +0100
+++ source/sound/oss/sb_card.h	2004-05-27 18:34:19.000000000 +0100
@@ -140,6 +140,8 @@
 	{.id = "RTL3000", .driver_data = 0, .devs = { {.id="@@@2001"},
 						     {.id="@X@2001"},
 						     {.id="@H@0001"}, } },
+	/* Sound Blaster 16 (Virtual PC 2004) */
+	{.id = "tBA03b0", .driver_data = 0, .devs = { {.id="PNPb003"}, } },
 	/* -end- */
 	{.id = "", }
 };
--- diff/sound/parisc/harmony.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/parisc/harmony.c	2004-05-27 18:34:19.000000000 +0100
@@ -56,11 +56,7 @@
  * also controls for enabling/disabling internal speaker and line
  * input.
  *
- * Buffers used by this driver are all DMA consistent. Since harmony is
- * not "real" pci device, we use a fake struct pci_dev for
- * pci_alloc_consistent().
- * (note that some machines -712 for ex.- don't implement DMA consistent
- * memory, so we will need to use kmalloc instead)
+ * Buffers used by this driver are all DMA consistent.
  */
 
 #include <linux/delay.h>
@@ -70,11 +66,11 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/info.h>
 #include <asm/hardware.h>
@@ -100,16 +96,14 @@
 #define MAX_PCM_SUBSTREAMS	4
 #define MAX_MIDI_DEVICES	0
 
-#define BUFFER_SIZE			4096
-#define MAX_BUFS			10
+#define HARMONY_BUF_SIZE	4096
+#define MAX_BUFS		10
+#define MAX_BUFFER_SIZE		(MAX_BUFS * HARMONY_BUF_SIZE)
 
 /* number of silence & graveyard buffers */
 #define GRAVEYARD_BUFS		3
 #define SILENCE_BUFS		3
 
-#define MAX_BUFFER_SIZE		(MAX_BUFS * BUFFER_SIZE)
-#define HARMONY_BUF_SIZE	BUFFER_SIZE
-
 #define HARMONY_CNTL_C		0x80000000
 
 #define HARMONY_DSTATUS_PN	0x00000200
@@ -140,6 +134,17 @@
 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;
+static int boot_devs;
+
+module_param_array(index, int, boot_devs, 0444);
+MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard.");
+MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
+module_param_array(id, charp, boot_devs, 0444);
+MODULE_PARM_DESC(id, "ID string for Sun CS4231 soundcard.");
+MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
+module_param_array(enable, bool, boot_devs, 0444);
+MODULE_PARM_DESC(enable, "Enable Sun CS4231 soundcard.");
+MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 
 /* Register offset (from base hpa) */
 #define REG_ID		0x00
@@ -191,21 +196,18 @@
 	int cap_stopped;
 	int cap_total;
 
-	struct pci_dev *fake_pci_dev; /* The fake pci_dev needed for 
-					pci_* functions under ccio. */
+	struct parisc_device *pa_dev;
+
+	struct snd_dma_device dma_dev;
 
 	/* the graveyard buffer is used as recording buffer when playback, 
 	 * because harmony always want a buffer to put recorded data */
-
-	unsigned char *graveyard_addr;
-	dma_addr_t graveyard_dma;
+	struct snd_dma_buffer graveyard_dma;
 	int graveyard_count;
 	
 	/* same thing for silence buffer */
-	unsigned char *silence_addr;
-	dma_addr_t silence_dma;
+	struct snd_dma_buffer silence_dma;
 	int silence_count;
-	struct snd_dma_device dma_dev;
 
 	/* alsa stuff */
 	snd_card_t *card;
@@ -264,6 +266,15 @@
 #define HARMONY_SR_33KHZ	0x16
 #define HARMONY_SR_6KHZ		0x17
 
+/* bits corresponding to the entries of snd_card_harmony_rates */
+static unsigned int rate_bits[14] = {
+	HARMONY_SR_5KHZ, HARMONY_SR_6KHZ, HARMONY_SR_8KHZ,
+	HARMONY_SR_9KHZ, HARMONY_SR_11KHZ, HARMONY_SR_16KHZ,
+	HARMONY_SR_18KHZ, HARMONY_SR_22KHZ, HARMONY_SR_27KHZ,
+	HARMONY_SR_32KHZ, HARMONY_SR_33KHZ, HARMONY_SR_37KHZ,
+	HARMONY_SR_44KHZ, HARMONY_SR_48KHZ
+};
+
 /* snd_card_harmony_rate_bits
  * @rate:	index of current data rate in list
  * returns: harmony hex code for registers
@@ -273,26 +284,9 @@
 	unsigned int idx;
 	
 	for (idx = 0; idx <= RATES; idx++)
-		if (snd_card_harmony_rates[idx] == rate) break;
-	
-	switch (idx) {
-		case 0: return HARMONY_SR_5KHZ;
-		case 1: return HARMONY_SR_6KHZ;
-		case 2: return HARMONY_SR_8KHZ;
-		case 3: return HARMONY_SR_9KHZ;
-		case 4: return HARMONY_SR_11KHZ;
-		case 5: return HARMONY_SR_16KHZ;
-		case 6: return HARMONY_SR_18KHZ;
-		case 7: return HARMONY_SR_22KHZ;
-		case 8: return HARMONY_SR_27KHZ;
-		case 9: return HARMONY_SR_32KHZ;
-		case 10: return HARMONY_SR_33KHZ;
-		case 11: return HARMONY_SR_37KHZ;
-		case 12: return HARMONY_SR_44KHZ;
-		case 13: return HARMONY_SR_48KHZ;
-		default:  /* fallback */
-				return HARMONY_SR_44KHZ;
-	}
+		if (snd_card_harmony_rates[idx] == rate)
+			return rate_bits[idx];
+	return HARMONY_SR_44KHZ; /* fallback */
 }
 
 /*
@@ -317,27 +311,6 @@
 }
 
 /*
- * silence a buffer
- * XXX: alsa could probably do this by itself
- * XXX: memset hpmc, commented.
- */
-
-void snd_harmony_silence(snd_card_harmony_t *harmony,
-		void *addr, int length)
-{
-	u8 silence_char;
-	
-	switch(harmony->data_format) {
-			case HARMONY_DF_8BIT_ULAW: silence_char = 0x55; break;
-			case HARMONY_DF_8BIT_ALAW: silence_char = 0xff; break;
-			case HARMONY_DF_16BIT_LINEAR:
-			default:
-									   silence_char = 0;
-	}
-	//memset(addr, silence_char, length);
-}
-
-/*
  * interruption controls routines
  */
 
@@ -385,9 +358,9 @@
 			snd_pcm_period_elapsed(harmony->playback_substream);
 			harmony->ply_total++;
 		} else {
-			gsc_writel(harmony->silence_dma + 
-					(HARMONY_BUF_SIZE*harmony->silence_count),
-					hpa+REG_PNXTADD);
+			gsc_writel(harmony->silence_dma.addr + 
+				   (HARMONY_BUF_SIZE*harmony->silence_count),
+				   hpa+REG_PNXTADD);
 			harmony->silence_count++;
 			harmony->silence_count %= SILENCE_BUFS;
 		}
@@ -406,9 +379,9 @@
 			harmony->cap_total++;
 		} else {
 			/* graveyard buffer */
-			gsc_writel(harmony->graveyard_dma +
-						(HARMONY_BUF_SIZE*harmony->graveyard_count),
-						hpa+REG_RNXTADD);
+			gsc_writel(harmony->graveyard_dma.addr +
+				   (HARMONY_BUF_SIZE*harmony->graveyard_count),
+				   hpa+REG_RNXTADD);
 			harmony->graveyard_count++;
 			harmony->graveyard_count %= GRAVEYARD_BUFS;
 		}
@@ -465,26 +438,8 @@
 {
 	snd_info_entry_t *entry;
 	
-	if ((entry = snd_info_create_card_entry(harmony->card, "harmony", harmony->card->proc_root)) != NULL) {
-		entry->content = SNDRV_INFO_CONTENT_TEXT;
-		entry->private_data = harmony;
-		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-		entry->c.text.read_size = 2048;	 /* should be enough */
-		entry->c.text.read = snd_harmony_proc_read;
-		if (snd_info_register(entry) < 0) {
-			snd_info_free_entry(entry);
-			entry = NULL;
-		}
-	}
-	harmony->proc_entry = entry;
-}
-
-static void snd_harmony_proc_done(snd_card_harmony_t *harmony)
-{
-	if (harmony->proc_entry) {
-		snd_info_unregister(harmony->proc_entry);
-		harmony->proc_entry = NULL;
-	}
+	if (! snd_card_proc_new(harmony->card, "harmony", &entry))
+		snd_info_set_text_ops(entry, harmony, 2048, snd_harmony_proc_read);
 }
 
 /* 
@@ -563,6 +518,30 @@
 	return 0;
 }
 
+/* set data format */
+static int snd_harmony_set_data_format(snd_card_harmony_t *harmony, int pcm_format)
+{
+	int old_format = harmony->data_format;
+	int new_format = old_format;
+	switch (pcm_format) {
+	case SNDRV_PCM_FORMAT_S16_BE:
+		new_format = HARMONY_DF_16BIT_LINEAR;
+		break;
+	case SNDRV_PCM_FORMAT_A_LAW:
+		new_format = HARMONY_DF_8BIT_ALAW;
+		break;
+	case SNDRV_PCM_FORMAT_MU_LAW:
+		new_format = HARMONY_DF_8BIT_ULAW;
+		break;
+	}
+	/* re-initialize silence buffer if needed */
+	if (old_format != new_format)
+		snd_pcm_format_set_silence(pcm_format, harmony->silence_dma.area,
+					   (HARMONY_BUF_SIZE * SILENCE_BUFS * 8) / snd_pcm_format_width(pcm_format));
+
+	return new_format;
+}
+
 static int snd_card_harmony_playback_prepare(snd_pcm_substream_t * substream)
 {
 	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
@@ -577,12 +556,13 @@
 	harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate);
 
 	/* data format */
-	if (snd_pcm_format_width(runtime->format) == 16) harmony->data_format = HARMONY_DF_16BIT_LINEAR;
-	else harmony->data_format = HARMONY_DF_8BIT_ULAW;
-	
+	harmony->data_format = snd_harmony_set_data_format(haromny, runtime->format);
+
 	/* number of channels */
-	if (runtime->channels == 2) harmony->stereo_select = HARMONY_SS_STEREO;
-	else harmony->stereo_select = HARMONY_SS_MONO;
+	if (runtime->channels == 2)
+		harmony->stereo_select = HARMONY_SS_STEREO;
+	else
+		harmony->stereo_select = HARMONY_SS_MONO;
 	
 	DPRINTK(KERN_INFO PFX "Playback_prepare, sr=%d(%x), df=%x, ss=%x hpa=%lx\n", runtime->rate,
 				harmony->sample_rate, harmony->data_format, harmony->stereo_select, harmony->hpa);
@@ -607,12 +587,13 @@
 	harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate);
 	
 	/* data format */
-	if (snd_pcm_format_width(runtime->format) == 16) harmony->data_format = HARMONY_DF_16BIT_LINEAR;
-	else harmony->data_format = HARMONY_DF_8BIT_ULAW;
+	harmony->data_format = snd_harmony_set_data_format(haromny, runtime->format);
 	
 	/* number of channels */
-	if (runtime->channels == 1) harmony->stereo_select = HARMONY_SS_MONO;
-	else if (runtime->channels == 2) harmony->stereo_select = HARMONY_SS_STEREO;
+	if (runtime->channels == 1)
+		harmony->stereo_select = HARMONY_SS_MONO;
+	else if (runtime->channels == 2)
+		harmony->stereo_select = HARMONY_SS_STEREO;
 		
 	snd_harmony_update_control(harmony);
 	harmony->format_initialized = 1;
@@ -709,13 +690,6 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	int err;
 	
-	/*
-	 * harmony is not "real" pci, but we need a pci_dev
-	 * to alloc PCI DMA pages
-	 */
-	substream->runtime->dma_private = harmony->fake_pci_dev;
-//	substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI;
-	
 	harmony->playback_substream = substream;
 	runtime->hw = snd_card_harmony_playback;
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);
@@ -732,14 +706,6 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	int err;
 	
-	
-	/*
-	 * harmony is not "real" pci, but we need a pci_dev
-	 * to alloc PCI DMA pages
-	 */
-	substream->runtime->dma_private = harmony->fake_pci_dev;
-//	substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI;
-
 	harmony->capture_substream = substream;
 	runtime->hw = snd_card_harmony_capture;
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);
@@ -752,7 +718,6 @@
 static int snd_card_harmony_playback_close(snd_pcm_substream_t * substream)
 {
 	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
-	snd_pcm_lib_free_pages(substream);
 	
 	harmony->playback_substream = NULL;
 	harmony->ply_size 			= 0;
@@ -769,8 +734,6 @@
 {
 	snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream);
 	
-	snd_pcm_lib_free_pages(substream);
-	
 	harmony->capture_substream = NULL;
 	harmony->cap_size 			= 0;
 	harmony->cap_buf			= 0;
@@ -785,12 +748,11 @@
 static int snd_card_harmony_hw_params(snd_pcm_substream_t *substream, 
 	                   snd_pcm_hw_params_t * hw_params)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
 	int err;
 	
 	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 	DPRINTK(KERN_INFO PFX "HW Params returned %d, dma_addr %lx\n", err,
-			(unsigned long)runtime->dma_addr);
+			(unsigned long)substream->runtime->dma_addr);
 	return err;
 }
 
@@ -847,15 +809,19 @@
 	harmony->pcm = pcm;
 	
 	/* initialize graveyard buffer */
-	harmony->dma_dev.type = SNDRV_DMA_TYPE_PCI;
-	harmony->dma_dev.dev = snd_dma_pci_data(harmony->fake_pci_dev); 
-	harmony->graveyard_addr = snd_dma_alloc_pages(&chip->dma_dev,
-			HARMONY_BUF_SIZE*GRAVEYARD_BUFS, &harmony->graveyard_dma);
+	harmony->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+	harmony->dma_dev.dev = &harmony->pa_dev->dev;
+	err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*GRAVEYARD_BUFS,
+				  &harmony->graveyard_dma);
+	if (err < 0)
+		return err;
 	harmony->graveyard_count = 0;
 	
 	/* initialize silence buffers */
-	harmony->silence_addr = snd_dma_alloc_pages(&chip->dma_dev,
-			HARMONY_BUF_SIZE*SILENCE_BUFS, &harmony->silence_dma);
+	err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*SILENCE_BUFS,
+				  &harmony->silence_dma);
+	if (err < 0)
+		return err;
 	harmony->silence_count = 0;
 
 	harmony->ply_stopped = harmony->cap_stopped = 1;
@@ -865,8 +831,8 @@
 	harmony->graveyard_count = 0;
 	
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-					      snd_dma_pci_data(harmony->fake_pci_dev),
-					      64 * 1024, 128 * 1024);
+					      &harmony->pa_dev->dev,
+					      MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
 
 	return 0;
 }
@@ -963,7 +929,7 @@
 HARMONY_VOLUME("PCM Playback Volume", 6, 0, 0x3f, 1),
 };
 
-static void snd_harmony_reset_codec(snd_card_harmony_t *harmony)
+static void __init snd_harmony_reset_codec(snd_card_harmony_t *harmony)
 {
  	snd_harmony_wait_cntl(harmony);
 	gsc_writel(1, harmony->hpa+REG_RESET);
@@ -985,7 +951,7 @@
 }
 
 
-int __init snd_card_harmony_mixer_init(snd_card_harmony_t *harmony)
+static int __init snd_card_harmony_mixer_init(snd_card_harmony_t *harmony)
 {
 	snd_card_t *card = harmony->card;
 	int idx, err;
@@ -1009,10 +975,11 @@
 	
 	harmony->card = card;
 	
+	harmony->pa_dev = pa_dev;
+
 	/* Set the HPA of harmony */
 	harmony->hpa = pa_dev->hpa;
 	
-
 	harmony->irq = pa_dev->irq;
 	if (!harmony->irq) {
 		printk(KERN_ERR PFX "no irq found\n");
@@ -1038,8 +1005,6 @@
 		return -EBUSY;
 	}
 	
-	/* a fake pci_dev is needed for pci_* functions under ccio */
-	harmony->fake_pci_dev = ccio_get_fake(pa_dev);
 	return 0;
 }
 	
@@ -1050,7 +1015,7 @@
 	snd_card_t *card;
 	int err;
 	
-    if (dev >= SNDRV_CARDS)
+	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
 	if (!enable[dev]) {
 		dev++;
@@ -1064,6 +1029,8 @@
 	if (card == NULL)
 		return -ENOMEM;
 	chip = (struct snd_card_harmony *)card->private_data;
+	spin_lock_init(&chip->control_lock);
+	spin_lock_init(&chip->mixer_lock);
 	
 	if ((err = snd_card_harmony_create(card, pa_dev, chip)) < 0) {
 		printk(KERN_ERR PFX "Creation failed\n");
@@ -1144,7 +1111,6 @@
 		{	
 			DPRINTK(KERN_INFO PFX "Freeing card %d\n", idx);
 			harmony = snd_harmony_cards[idx]->private_data;
-			snd_harmony_proc_done(harmony);
 			free_irq(harmony->irq, snd_card_harmony_interrupt);
 			printk(KERN_INFO PFX "Card unloaded %d, irq=%d\n", idx, harmony->irq);
 			snd_card_free(snd_harmony_cards[idx]);
--- diff/sound/pci/Kconfig	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/Kconfig	2004-05-27 18:34:19.000000000 +0100
@@ -16,11 +16,11 @@
 	  Say 'Y' or 'M' to include support for ALI PCI Audio M5451 sound core.
 
 config SND_ATIIXP
-	tristate "ATI IXP 150/200/250"
+	tristate "ATI IXP 150/200/250/300"
 	depends on SND
 	select SND_AC97_CODEC
 	help
-	  Say 'Y' or 'M' to include support for ATI IXP 150/200/250 AC97 controller.
+	  Say 'Y' or 'M' to include support for ATI IXP 150/200/250/300 AC97 controller.
 
 config SND_AU8810
         tristate "Aureal Advantage"
@@ -29,6 +29,9 @@
 	select SND_AC97_CODEC
         help
           Say 'Y' or 'M' to include support for Aureal Advantage soundcards.
+          Supported features: Hardware Mixer, SRC, EQ and SPDIF output.
+          3D support code is in place, but not yet useable. For more info, 
+          email the ALSA developer list, or mjander@users.sourceforge.net.
  
 config SND_AU8820
         tristate "Aureal Vortex"
@@ -37,6 +40,8 @@
 	select SND_AC97_CODEC
         help
           Say 'Y' or 'M' to include support for Aureal Vortex soundcards.
+          Supported features: Hardware Mixer and SRC. For more info, email 
+          the ALSA developer list, or mjander@users.sourceforge.net.
  
 config SND_AU8830
         tristate "Aureal Vortex 2"
@@ -45,6 +50,9 @@
 	select SND_AC97_CODEC
         help
           Say 'Y' or 'M' to include support for Aureal Vortex 2 soundcards.
+          Supported features: Hardware Mixer, SRC, EQ and SPDIF output.
+          3D support code is in place, but not yet useable. For more info, 
+          email the ALSA developer list, or mjander@users.sourceforge.net.
  
 config SND_AZT3328
 	tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)"
@@ -262,15 +270,15 @@
 	  TerraTec - EWX 24/96, EWS 88MT, EWS 88D, DMX 6Fire.
 
 config SND_ICE1724
-	tristate "ICE/VT1724 (Envy24HT)"
+	tristate "ICE/VT1724/1720 (Envy24HT/PT)"
 	depends on SND
 	select SND_MPU401_UART
 	select SND_AC97_CODEC
 	help
-	  Say 'Y' or 'M' to include support for ICE/VT1724 (Envy24HT) based
+	  Say 'Y' or 'M' to include support for ICE/VT1724/1720 (Envy24HT/PT) based
 	  soundcards.
 	  Currently supported hardware is: MidiMan M Audio - Revolution 7.1,
-	  AMP Ltd AUDIO2000.
+	  AMP Ltd AUDIO2000, Terratec Aureon 5.1 Sky/7.1, AudioTrak Prodigy 7.1.
 
 config SND_INTEL8X0
 	tristate "Intel i8x0/MX440, SiS 7012; Ali 5455; NForce Audio; AMD768/8111"
--- diff/sound/pci/ac97/ac97_codec.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ac97/ac97_codec.c	2004-05-27 18:34:19.000000000 +0100
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -42,7 +43,7 @@
 
 static int enable_loopback;
 
-MODULE_PARM(enable_loopback, "i");
+module_param(enable_loopback, bool, 0444);
 MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
 MODULE_PARM_SYNTAX(enable_loopback, SNDRV_BOOLEAN_FALSE_DESC);
 
@@ -299,6 +300,16 @@
 	return ac97->bus->read(ac97, reg);
 }
 
+/* read a register - return the cached value if already read */
+static inline unsigned short snd_ac97_read_cache(ac97_t *ac97, unsigned short reg)
+{
+	if (! test_bit(reg, ac97->reg_accessed)) {
+		ac97->regs[reg] = ac97->bus->read(ac97, reg);
+		// set_bit(reg, ac97->reg_accessed);
+	}
+	return ac97->regs[reg];
+}
+
 /**
  * snd_ac97_write_cache - write a value on the given register and update the cache
  * @ac97: the ac97 instance
@@ -370,7 +381,7 @@
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return -EINVAL;
 	spin_lock(&ac97->reg_lock);
-	old = ac97->regs[reg];
+	old = snd_ac97_read_cache(ac97, reg);
 	new = (old & ~mask) | value;
 	change = old != new;
 	if (change) {
@@ -385,25 +396,26 @@
 static int snd_ac97_ad18xx_update_pcm_bits(ac97_t *ac97, int codec, unsigned short mask, unsigned short value)
 {
 	int change;
-	unsigned short old, new;
+	unsigned short old, new, cfg;
 
 	down(&ac97->spec.ad18xx.mutex);
 	spin_lock(&ac97->reg_lock);
 	old = ac97->spec.ad18xx.pcmreg[codec];
 	new = (old & ~mask) | value;
+	cfg = snd_ac97_read_cache(ac97, AC97_AD_SERIAL_CFG);
 	change = old != new;
 	if (change) {
 		ac97->spec.ad18xx.pcmreg[codec] = new;
 		spin_unlock(&ac97->reg_lock);
 		/* select single codec */
 		ac97->bus->write(ac97, AC97_AD_SERIAL_CFG,
-				 (ac97->regs[AC97_AD_SERIAL_CFG] & ~0x7000) |
+				 (cfg & ~0x7000) |
 				 ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
 		/* update PCM bits */
 		ac97->bus->write(ac97, AC97_PCM, new);
 		/* select all codecs */
 		ac97->bus->write(ac97, AC97_AD_SERIAL_CFG,
-				 ac97->regs[AC97_AD_SERIAL_CFG] | 0x7000);
+				 cfg | 0x7000);
 	} else
 		spin_unlock(&ac97->reg_lock);
 	up(&ac97->spec.ad18xx.mutex);
@@ -435,7 +447,7 @@
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
 	
-	val = ac97->regs[AC97_REC_SEL];
+	val = snd_ac97_read_cache(ac97, AC97_REC_SEL);
 	ucontrol->value.enumerated.item[0] = (val >> 8) & 7;
 	ucontrol->value.enumerated.item[1] = (val >> 0) & 7;
 	return 0;
@@ -493,7 +505,7 @@
 	int shift = (kcontrol->private_value >> 8) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0xff;
 	
-	val = (ac97->regs[reg] >> shift) & 1;
+	val = (snd_ac97_read_cache(ac97, reg) >> shift) & 1;
 	if (invert)
 		val ^= 1;
 	ucontrol->value.enumerated.item[0] = val;
@@ -535,7 +547,7 @@
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0xff;
 	
-	ucontrol->value.integer.value[0] = (ac97->regs[reg] >> shift) & mask;
+	ucontrol->value.integer.value[0] = (snd_ac97_read_cache(ac97, reg) >> shift) & mask;
 	if (invert)
 		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
 	return 0;
@@ -582,8 +594,8 @@
 	int invert = (kcontrol->private_value >> 24) & 0xff;
 	
 	spin_lock(&ac97->reg_lock);
-	ucontrol->value.integer.value[0] = (ac97->regs[reg] >> shift_left) & mask;
-	ucontrol->value.integer.value[1] = (ac97->regs[reg] >> shift_right) & mask;
+	ucontrol->value.integer.value[0] = (snd_ac97_read_cache(ac97, reg) >> shift_left) & mask;
+	ucontrol->value.integer.value[1] = (snd_ac97_read_cache(ac97, reg) >> shift_right) & mask;
 	spin_unlock(&ac97->reg_lock);
 	if (invert) {
 		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
@@ -796,7 +808,7 @@
 					       AC97_CXR_SPDIF_MASK | AC97_CXR_COPYRGT,
 					       v);
 	} else {
-		unsigned short extst = ac97->regs[AC97_EXTENDED_STATUS];
+		unsigned short extst = snd_ac97_read_cache(ac97, AC97_EXTENDED_STATUS);
 		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); /* turn off */
 
 		change |= snd_ac97_update_bits(ac97, AC97_SPDIF, 0x3fff, val);
@@ -822,13 +834,13 @@
 	mask <<= shift;
 	value <<= shift;
 	spin_lock(&ac97->reg_lock);
-	old = ac97->regs[reg];
+	old = snd_ac97_read_cache(ac97, reg);
 	new = (old & ~mask) | value;
 	spin_unlock(&ac97->reg_lock);
 
 	if (old != new) {
 		int change;
-		unsigned short extst = ac97->regs[AC97_EXTENDED_STATUS];
+		unsigned short extst = snd_ac97_read_cache(ac97, AC97_EXTENDED_STATUS);
 		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); /* turn off */
 		change = snd_ac97_update_bits(ac97, reg, mask, value);
 		if (extst & AC97_EA_SPDIF)
@@ -868,14 +880,14 @@
 		.info = snd_ac97_info_single,
 		.get = snd_ac97_get_single,
 		.put = snd_ac97_put_spsa,
-		.private_value = AC97_EXTENDED_STATUS | (4 << 8) | (3 << 16) | (0 << 24),
+		.private_value = AC97_SINGLE_VALUE(AC97_EXTENDED_STATUS, 4, 3, 0)
 	},
 };
 
 #define AD18XX_PCM_BITS(xname, codec, lshift, rshift, mask) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_bits, \
   .get = snd_ac97_ad18xx_pcm_get_bits, .put = snd_ac97_ad18xx_pcm_put_bits, \
-  .private_value = (codec) | ((lshift) << 8) | ((rshift) << 12) | ((mask) << 24) }
+  .private_value = (codec) | ((lshift) << 8) | ((rshift) << 12) | ((mask) << 16) }
 
 static int snd_ac97_ad18xx_pcm_info_bits(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
@@ -987,6 +999,8 @@
  *
  */
 
+static void snd_ac97_powerdown(ac97_t *ac97);
+
 static int snd_ac97_bus_free(ac97_bus_t *bus)
 {
 	if (bus) {
@@ -1022,6 +1036,7 @@
 static int snd_ac97_dev_free(snd_device_t *device)
 {
 	ac97_t *ac97 = snd_magic_cast(ac97_t, device->device_data, return -ENXIO);
+	snd_ac97_powerdown(ac97); /* for avoiding click noises during shut down */
 	return snd_ac97_free(ac97);
 }
 
@@ -1572,6 +1587,26 @@
 	*r_result = result;
 }
 
+/* check AC97_SPDIF register to accept which sample rates */
+static unsigned int snd_ac97_determine_spdif_rates(ac97_t *ac97)
+{
+	unsigned int result = 0;
+	int i;
+	static unsigned short ctl_bits[] = {
+		AC97_SC_SPSR_44K, AC97_SC_SPSR_32K, AC97_SC_SPSR_48K
+	};
+	static unsigned int rate_bits[] = {
+		SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_32000, SNDRV_PCM_RATE_48000
+	};
+
+	for (i = 0; i < (int)ARRAY_SIZE(ctl_bits); i++) {
+		snd_ac97_update_bits(ac97, AC97_SPDIF, AC97_SC_SPSR_MASK, ctl_bits[i]);
+		if ((snd_ac97_read(ac97, AC97_SPDIF) & AC97_SC_SPSR_MASK) == ctl_bits[i])
+			result |= rate_bits[i];
+	}
+	return result;
+}
+
 void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem)
 {
 	const ac97_codec_id_t *pid;
@@ -1889,9 +1924,7 @@
 		else if (ac97->id == AC97_ID_CM9739)
 			ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000;
 		else
-			ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 |
-						SNDRV_PCM_RATE_44100 |
-						SNDRV_PCM_RATE_32000;
+			ac97->rates[AC97_RATES_SPDIF] = snd_ac97_determine_spdif_rates(ac97);
 	}
 	if (ac97->ext_id & AC97_EI_VRM) {	/* MIC VRA support */
 		snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]);
@@ -1949,12 +1982,12 @@
 	}
 	/* make sure the proper powerdown bits are cleared */
 	if (ac97->scaps) {
-		reg = snd_ac97_read(ac97, AC97_EXTENDED_ID);
+		reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
 		if (ac97->scaps & AC97_SCAP_SURROUND_DAC) 
 			reg &= ~AC97_EA_PRJ;
 		if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) 
 			reg &= ~(AC97_EA_PRI | AC97_EA_PRK);
-		snd_ac97_write_cache(ac97, AC97_EXTENDED_ID, reg);
+		snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg);
 	}
 	snd_ac97_proc_init(ac97);
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) {
@@ -1965,17 +1998,24 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-/**
- * snd_ac97_suspend - General suspend function for AC97 codec
- * @ac97: the ac97 instance
+
+/*
+ * Power down the chip.
  *
- * Suspends the codec, power down the chip.
+ * MASTER and HEADPHONE registers are muted but the register cache values
+ * are not changed, so that the values can be restored in snd_ac97_resume().
  */
-void snd_ac97_suspend(ac97_t *ac97)
+static void snd_ac97_powerdown(ac97_t *ac97)
 {
-	unsigned short power = (ac97->regs[AC97_POWERDOWN] ^ 0x8000) & ~0x8000;	/* invert EAPD */
+	unsigned short power;
+
+	if (ac97_is_audio(ac97)) {
+		/* some codecs have stereo mute bits */
+		snd_ac97_write(ac97, AC97_MASTER, 0x9f9f);
+		snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f);
+	}
 
+	power = ac97->regs[AC97_POWERDOWN] | 0x8000;	/* EAPD */
 	power |= 0x4000;	/* Headphone amplifier powerdown */
 	power |= 0x0300;	/* ADC & DAC powerdown */
 	snd_ac97_write(ac97, AC97_POWERDOWN, power);
@@ -1983,8 +2023,24 @@
 	power |= 0x0400;	/* Analog Mixer powerdown (Vref on) */
 	snd_ac97_write(ac97, AC97_POWERDOWN, power);
 	udelay(100);
+#if 0
+	/* FIXME: this causes click noises on some boards at resume */
 	power |= 0x3800;	/* AC-link powerdown, internal Clk disable */
 	snd_ac97_write(ac97, AC97_POWERDOWN, power);
+#endif
+}
+
+
+#ifdef CONFIG_PM
+/**
+ * snd_ac97_suspend - General suspend function for AC97 codec
+ * @ac97: the ac97 instance
+ *
+ * Suspends the codec, power down the chip.
+ */
+void snd_ac97_suspend(ac97_t *ac97)
+{
+	snd_ac97_powerdown(ac97);
 }
 
 /**
@@ -2267,6 +2323,7 @@
 EXPORT_SYMBOL(snd_ac97_set_rate);
 #ifdef CONFIG_PM
 EXPORT_SYMBOL(snd_ac97_resume);
+EXPORT_SYMBOL(snd_ac97_suspend);
 #endif
 
 /*
--- diff/sound/pci/ac97/ac97_local.h	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ac97/ac97_local.h	2004-05-27 18:34:19.000000000 +0100
@@ -22,10 +22,11 @@
  *
  */
 
+#define AC97_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24))
 #define AC97_SINGLE(xname, reg, shift, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \
   .get = snd_ac97_get_single, .put = snd_ac97_put_single, \
-  .private_value = (reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24) }
+  .private_value =  AC97_SINGLE_VALUE(reg, shift, mask, invert) }
 
 /* ac97_codec.c */
 extern const char *snd_ac97_stereo_enhancements[];
--- diff/sound/pci/ac97/ac97_patch.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ac97/ac97_patch.c	2004-05-27 18:34:19.000000000 +0100
@@ -447,18 +447,198 @@
 	return 0;
 }
 
+static int snd_ac97_stac9758_output_jack_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[5] = { "Input/Disabled", "Front Output",
+		"Rear Output", "Center/LFE Output", "Mixer Output" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 5;
+	if (uinfo->value.enumerated.item > 4)
+		uinfo->value.enumerated.item = 4;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_stac9758_output_jack_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value;
+	unsigned short val;
+
+	val = ac97->regs[AC97_SIGMATEL_OUTSEL];
+	if (!((val >> shift) & 4))
+		ucontrol->value.enumerated.item[0] = 0;
+	else
+		ucontrol->value.enumerated.item[0] = 1 + ((val >> shift) & 3);
+	return 0;
+}
+
+static int snd_ac97_stac9758_output_jack_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value;
+	unsigned short val;
+
+	if (ucontrol->value.enumerated.item[0] > 4)
+		return -EINVAL;
+	if (ucontrol->value.enumerated.item[0] == 0)
+		val = 0;
+	else
+		val = 4 | (ucontrol->value.enumerated.item[0] - 1);
+	return snd_ac97_update_bits(ac97, AC97_SIGMATEL_OUTSEL,
+				    7 << shift, val << shift);
+}
+
+static int snd_ac97_stac9758_input_jack_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[7] = { "Mic2 Jack", "Mic1 Jack", "Line In Jack",
+		"Front Jack", "Rear Jack", "Center/LFE Jack", "Mute" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 7;
+	if (uinfo->value.enumerated.item > 6)
+		uinfo->value.enumerated.item = 6;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_stac9758_input_jack_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value;
+	unsigned short val;
+
+	val = ac97->regs[AC97_SIGMATEL_INSEL];
+	ucontrol->value.enumerated.item[0] = (val >> shift) & 7;
+	return 0;
+}
+
+static int snd_ac97_stac9758_input_jack_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value;
+
+	return snd_ac97_update_bits(ac97, AC97_SIGMATEL_INSEL, 7 << shift,
+				    ucontrol->value.enumerated.item[0] << shift);
+}
+
+static int snd_ac97_stac9758_phonesel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[3] = { "None", "Front Jack", "Rear Jack" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+	if (uinfo->value.enumerated.item > 2)
+		uinfo->value.enumerated.item = 2;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_stac9758_phonesel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.enumerated.item[0] = ac97->regs[AC97_SIGMATEL_IOMISC] & 3;
+	return 0;
+}
+
+static int snd_ac97_stac9758_phonesel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+	return snd_ac97_update_bits(ac97, AC97_SIGMATEL_IOMISC, 3,
+				    ucontrol->value.enumerated.item[0]);
+}
+
+#define STAC9758_OUTPUT_JACK(xname, shift) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_ac97_stac9758_output_jack_info, \
+	.get = snd_ac97_stac9758_output_jack_get, \
+	.put = snd_ac97_stac9758_output_jack_put, \
+	.private_value = shift }
+#define STAC9758_INPUT_JACK(xname, shift) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_ac97_stac9758_input_jack_info, \
+	.get = snd_ac97_stac9758_input_jack_get, \
+	.put = snd_ac97_stac9758_input_jack_put, \
+	.private_value = shift }
+static const snd_kcontrol_new_t snd_ac97_sigmatel_stac9758_controls[] = {
+	STAC9758_OUTPUT_JACK("Mic1 Jack", 1),
+	STAC9758_OUTPUT_JACK("LineIn Jack", 4),
+	STAC9758_OUTPUT_JACK("Front Jack", 7),
+	STAC9758_OUTPUT_JACK("Rear Jack", 10),
+	STAC9758_OUTPUT_JACK("Center/LFE Jack", 13),
+	STAC9758_INPUT_JACK("Mic Input Source", 0),
+	STAC9758_INPUT_JACK("Line Input Source", 8),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Headphone Amp",
+		.info = snd_ac97_stac9758_phonesel_info,
+		.get = snd_ac97_stac9758_phonesel_get,
+		.put = snd_ac97_stac9758_phonesel_put
+	},
+	AC97_SINGLE("Exchange Center/LFE", AC97_SIGMATEL_IOMISC, 4, 1, 0),
+	AC97_SINGLE("Headphone +3dB Boost", AC97_SIGMATEL_IOMISC, 8, 1, 0)
+};
+
+static int patch_sigmatel_stac9758_specific(ac97_t *ac97)
+{
+	int err;
+
+	err = patch_sigmatel_stac97xx_specific(ac97);
+	if (err < 0)
+		return err;
+	err = patch_build_controls(ac97, snd_ac97_sigmatel_stac9758_controls,
+				   ARRAY_SIZE(snd_ac97_sigmatel_stac9758_controls));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = {
+	.build_3d	= patch_sigmatel_stac9700_3d,
+	.build_specific	= patch_sigmatel_stac9758_specific
+};
+
 int patch_sigmatel_stac9758(ac97_t * ac97)
 {
+	static unsigned short regs[4] = {
+		AC97_SIGMATEL_OUTSEL,
+		AC97_SIGMATEL_IOMISC,
+		AC97_SIGMATEL_INSEL,
+		AC97_SIGMATEL_VARIOUS
+	};
+	static unsigned short def_regs[4] = {
+		/* OUTSEL */ 0xd794,
+		/* IOMISC */ 0x2001,
+		/* INSEL */ 0x0201,
+		/* VARIOUS */ 0x0040
+	};
+	static unsigned short m675_regs[4] = {
+		/* OUTSEL */ 0x9040,
+		/* IOMISC */ 0x2102,
+		/* INSEL */ 0x0203,
+		/* VARIOUS */ 0x0041
+	};
+	unsigned short *pregs = def_regs;
+	int i;
+
+	/* Gateway M675 notebook */
+	if (ac97->pci && 
+	    ac97->subsystem_vendor == 0x107b &&
+	    ac97->subsystem_device == 0x0601)
+	    	pregs = m675_regs;
+
 	// patch for SigmaTel
-	ac97->build_ops = &patch_sigmatel_stac9700_ops;
-	// turn on stereo speaker, headphone and line-out
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_OUTSEL, 0x9040);
-	// headphone select and boost
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_IOMISC, 0x2102);
-	// enable mic
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_INSEL, 0x0203);
-	// enable stereo mic
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_VARIOUS, 0x0001);
+	ac97->build_ops = &patch_sigmatel_stac9758_ops;
+	for (i = 0; i < 4; i++)
+		snd_ac97_write_cache(ac97, regs[i], pregs[i]);
+
+	ac97->flags |= AC97_STEREO_MUTES;
 	return 0;
 }
 
@@ -1027,6 +1207,8 @@
 			     AC97_AD198X_MSPLT |
 			     AC97_AD198X_AC97NC);
 	ac97->flags |= AC97_STEREO_MUTES;
+	/* on AD1985 rev. 3, AC'97 revision bits are zero */
+	ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23;
 	return 0;
 }
 
@@ -1088,6 +1270,7 @@
 		.info = snd_ac97_info_single,
 		.get = snd_ac97_alc650_mic_get,
 		.put = snd_ac97_alc650_mic_put,
+		.private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
 	},
 };
 
@@ -1188,6 +1371,7 @@
 		.info = snd_ac97_info_single,
 		.get = snd_ac97_alc655_mic_get,
 		.put = snd_ac97_alc655_mic_put,
+		.private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
 	},
 };
 
@@ -1358,8 +1542,34 @@
 	/* BIT 8: SPD32 - 32bit SPDIF - not supported yet */
 };
 
+static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000)
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
+				    ucontrol->value.integer.value[0] ? 
+				    0x1000 : 0x2000);
+}
+
 static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = {
 	AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic As Center/LFE",
+		.info = snd_ac97_info_single,
+		.get = snd_ac97_cm9739_center_mic_get,
+		.put = snd_ac97_cm9739_center_mic_put,
+		.private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
+	},
 };
 
 static int patch_cm9739_specific(ac97_t * ac97)
@@ -1394,10 +1604,13 @@
 	}
 
 	/* set-up multi channel */
-	/* bit 13: enable internal vref output for mic */
-	/* bit 12: enable center/lfe */
 	/* bit 14: 0 = SPDIF, 1 = EAPD */
-	val = (1 << 12) | (1 << 13);
+	/* bit 13: enable internal vref output for mic */
+	/* bit 12: disable center/lfe (swithable) */
+	/* bit 10: disable surround/line (switchable) */
+	/* bit 9: mix 2 surround off */
+	/* bit 0: dB */
+	val = (1 << 13);
 	if (! (ac97->ext_id & AC97_EI_SPDIF))
 		val |= (1 << 14);
 	snd_ac97_write_cache(ac97, AC97_CM9739_MULTI_CHAN, val);
--- diff/sound/pci/ac97/ac97_pcm.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ac97/ac97_pcm.c	2004-05-27 18:34:19.000000000 +0100
@@ -210,7 +210,7 @@
 	}
 
 	spin_lock(&ac97->reg_lock);
-	old = ac97->regs[reg] & mask;
+	old = snd_ac97_read(ac97, reg) & mask;
 	spin_unlock(&ac97->reg_lock);
 	if (old != bits) {
 		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
--- diff/sound/pci/ac97/ac97_proc.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ac97/ac97_proc.c	2004-05-27 18:34:19.000000000 +0100
@@ -34,6 +34,40 @@
  * proc interface
  */
 
+static void snd_ac97_proc_read_functions(ac97_t *ac97, snd_info_buffer_t *buffer)
+{
+	int header = 0, function;
+	unsigned short info, sense_info;
+	static const char *function_names[12] = {
+		"Master Out", "AUX Out", "Center/LFE Out", "SPDIF Out",
+		"Phone In", "Mic 1", "Mic 2", "Line In", "CD In", "Video In",
+		"Aux In", "Mono Out"
+	};
+	static const char *locations[8] = {
+		"Rear I/O Panel", "Front Panel", "Motherboard", "Dock/External",
+		"reserved", "reserved", "reserved", "NC/unused"
+	};
+
+	for (function = 0; function < 12; ++function) {
+		snd_ac97_write(ac97, AC97_FUNC_SELECT, function << 1);
+		info = snd_ac97_read(ac97, AC97_FUNC_INFO);
+		if (!(info & 0x0001))
+			continue;
+		if (!header) {
+			snd_iprintf(buffer, "\n                    Gain     Inverted  Buffer delay  Location\n");
+			header = 1;
+		}
+		sense_info = snd_ac97_read(ac97, AC97_SENSE_INFO);
+		snd_iprintf(buffer, "%-17s: %3d.%d dBV    %c      %2d/fs         %s\n",
+			    function_names[function],
+			    (info & 0x8000 ? -1 : 1) * ((info & 0x7000) >> 12) * 3 / 2,
+			    ((info & 0x0800) >> 11) * 5,
+			    info & 0x0400 ? 'X' : '-',
+			    (info & 0x03e0) >> 5,
+			    locations[sense_info >> 13]);
+	}
+}
+
 static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx)
 {
 	char name[64];
@@ -47,6 +81,21 @@
 	if ((ac97->scaps & AC97_SCAP_AUDIO) == 0)
 		goto __modem;
 
+	if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23) {
+		val = snd_ac97_read(ac97, AC97_INT_PAGING);
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING,
+				     AC97_PAGE_MASK, AC97_PAGE_1);
+		tmp = snd_ac97_read(ac97, AC97_CODEC_CLASS_REV);
+		snd_iprintf(buffer, "Revision         : 0x%02x\n", tmp & 0xff);
+		snd_iprintf(buffer, "Compat. Class    : 0x%02x\n", (tmp >> 8) & 0x1f);
+		snd_iprintf(buffer, "Subsys. Vendor ID: 0x%04x\n",
+			    snd_ac97_read(ac97, AC97_PCI_SVID));
+		snd_iprintf(buffer, "Subsys. ID       : 0x%04x\n\n",
+			    snd_ac97_read(ac97, AC97_PCI_SID));
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING,
+				     AC97_PAGE_MASK, val & AC97_PAGE_MASK);
+	}
+
 	// val = snd_ac97_read(ac97, AC97_RESET);
 	val = ac97->caps;
 	snd_iprintf(buffer, "Capabilities     :%s%s%s%s%s%s\n",
@@ -185,6 +234,14 @@
 			}
 		}
 	}
+	if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23) {
+		val = snd_ac97_read(ac97, AC97_INT_PAGING);
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING,
+				     AC97_PAGE_MASK, AC97_PAGE_1);
+		snd_ac97_proc_read_functions(ac97, buffer);
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING,
+				     AC97_PAGE_MASK, val & AC97_PAGE_MASK);
+	}
 
 
       __modem:
@@ -264,6 +321,23 @@
 	}
 }
 
+#ifdef CONFIG_SND_DEBUG
+/* direct register write for debugging */
+static void snd_ac97_proc_regs_write(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+	ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
+	char line[64];
+	unsigned int reg, val;
+	while (!snd_info_get_line(buffer, line, sizeof(line))) {
+		if (sscanf(line, "%x %x", &reg, &val) != 2)
+			continue;
+		/* register must be odd */
+		if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff)
+			snd_ac97_write_cache(ac97, reg, val);
+	}
+}
+#endif
+
 static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx)
 {
 	int reg, val;
@@ -319,6 +393,11 @@
 	sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num);
 	if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) {
 		snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_regs_read);
+#ifdef CONFIG_SND_DEBUG
+		entry->mode |= S_IWUSR;
+		entry->c.text.write_size = 1024;
+		entry->c.text.write = snd_ac97_proc_regs_write;
+#endif
 		if (snd_info_register(entry) < 0) {
 			snd_info_free_entry(entry);
 			entry = NULL;
--- diff/sound/pci/ali5451/ali5451.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ali5451/ali5451.c	2004-05-27 18:34:19.000000000 +0100
@@ -25,8 +25,6 @@
  *
  */
 
-#define __SNDRV_OSS_COMPAT__
-
 #include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
@@ -34,12 +32,12 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
 #include <sound/ac97_codec.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Matt Wu <Matt_Wu@acersoftech.com.cn>");
@@ -53,20 +51,21 @@
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 32};
 static int spdif[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for ALI M5451 PCI Audio.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable ALI 5451 PCI Audio.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(pcm_channels, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(pcm_channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_channels, "PCM Channels");
 MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",default:32,allows:{{1,32}}");
-MODULE_PARM(spdif, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(spdif, bool, boot_devs, 0444);
 MODULE_PARM_DESC(spdif, "Support SPDIF I/O");
 MODULE_PARM_SYNTAX(spdif, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 
@@ -1906,14 +1905,18 @@
 }
 
 #ifdef CONFIG_PM
-static void ali_suspend(ali_t *chip)
+static int ali_suspend(snd_card_t *card, unsigned int state)
 {
+	ali_t *chip = snd_magic_cast(ali_t, card->pm_private_data, return -EINVAL);
 	ali_image_t *im;
 	int i, j;
 
 	im = chip->image;
 	if (! im)
-		return;
+		return 0;
+
+	snd_pcm_suspend_all(chip->pcm);
+	snd_ac97_suspend(chip->ac97);
 
 	spin_lock_irq(&chip->reg_lock);
 	
@@ -1940,16 +1943,18 @@
 	outl(0xffffffff, ALI_REG(chip, ALI_STOP));
 
 	spin_unlock_irq(&chip->reg_lock);
+	return 0;
 }
 
-static void ali_resume(ali_t *chip)
+static int ali_resume(snd_card_t *card, unsigned int state)
 {
+	ali_t *chip = snd_magic_cast(ali_t, card->pm_private_data, return -EINVAL);
 	ali_image_t *im;
 	int i, j;
 
 	im = chip->image;
 	if (! im)
-		return;
+		return 0;
 
 	pci_enable_device(chip->pci);
 
@@ -1967,27 +1972,15 @@
 		outl(im->regs[i], ALI_REG(chip, i*4));
 	}
 	
-	snd_ac97_resume(chip->ac97);
-	
 	// start HW channel
 	outl(im->regs[ALI_START >> 2], ALI_REG(chip, ALI_START));
 	// restore IRQ enable bits
 	outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT));
 	
 	spin_unlock_irq(&chip->reg_lock);
-	return;
-}
 
-static int snd_ali_suspend(struct pci_dev *dev, u32 state)
-{
-	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return -ENXIO);
-	ali_suspend(chip);
-	return 0;
-}
-static int snd_ali_resume(struct pci_dev *dev)
-{
-	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return -ENXIO);
-	ali_resume(chip);
+	snd_ac97_resume(chip->ac97);
+	
 	return 0;
 }
 #endif /* CONFIG_PM */
@@ -2203,7 +2196,9 @@
 #ifdef CONFIG_PM
 	codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);
 	if (! codec->image)
-		snd_printk("can't allocate apm buffer\n");
+		snd_printk(KERN_WARNING "can't allocate apm buffer\n");
+	else
+		snd_card_set_pm_callback(card, ali_suspend, ali_resume, codec);
 #endif
 
 	snd_ali_enable_address_interrupt(codec);
@@ -2263,16 +2258,14 @@
 		snd_card_free(card);
 		return err;
 	}
-	pci_set_drvdata(pci, codec);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_ali_remove(struct pci_dev *pci)
 {
-	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -2281,23 +2274,12 @@
 	.id_table = snd_ali_ids,
 	.probe = snd_ali_probe,
 	.remove = __devexit_p(snd_ali_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_ali_suspend,
-	.resume = snd_ali_resume,
-#endif
+	SND_PCI_PM_CALLBACKS
 };                                
 
 static int __init alsa_card_ali_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "ALi pci audio not found or device busy.\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_ali_exit(void)
@@ -2307,25 +2289,3 @@
 
 module_init(alsa_card_ali_init)
 module_exit(alsa_card_ali_exit)
-
-#ifndef MODULE
-
-/* format is: snd-ali5451=enable,index,id,pcm_channels */
-
-static int __init alsa_card_ali_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 &&
-	       get_option(&str,&pcm_channels[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-ali5451=", alsa_card_ali_setup);
-
-#endif /* ifndef */
--- diff/sound/pci/als4000.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/als4000.c	2004-05-27 18:34:19.000000000 +0100
@@ -64,13 +64,13 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 #include <sound/sb.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>");
@@ -89,18 +89,19 @@
 #ifdef SUPPORT_JOYSTICK
 static int joystick_port[SNDRV_CARDS];
 #endif
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for ALS4000 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for ALS4000 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable ALS4000 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC);
 #ifdef SUPPORT_JOYSTICK
-MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick_port, int, boot_devs, 0444);
 MODULE_PARM_DESC(joystick_port, "Joystick port address for ALS4000 soundcard. (0 = disabled)");
 MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED);
 #endif
@@ -755,15 +756,7 @@
 
 static int __init alsa_card_als4000_init(void)
 {
-	int err;
-	
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "no ALS4000 based soundcards found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_als4000_exit(void)
@@ -773,28 +766,3 @@
 
 module_init(alsa_card_als4000_init)
 module_exit(alsa_card_als4000_exit)
-
-#ifndef MODULE
-
-/* format is: snd-als4000=enable,index,id,joystick_port */
-
-static int __init alsa_card_als4000_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
-#ifdef SUPPORT_JOYSTICK
-	       && get_option(&str,&joystick_port[nr_dev]) == 2
-#endif
-	       );
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-als4000=", alsa_card_als4000_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/atiixp.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/atiixp.c	2004-05-27 18:34:19.000000000 +0100
@@ -26,39 +26,40 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <sound/ac97_codec.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ATI IXP AC97 controller");
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{ATI,IXP150/200/250}}");
+MODULE_DEVICES("{{ATI,IXP150/200/250/300}}");
 
 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 */
 static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
 static int spdif_aclink[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for ATI IXP controller.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable audio part of ATI IXP controller.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ac97_clock, int, boot_devs, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
 MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000");
-MODULE_PARM(spdif_aclink, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(spdif_aclink, bool, boot_devs, 0444);
 MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
 MODULE_PARM_SYNTAX(spdif_aclink, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
 
@@ -223,7 +224,12 @@
 /*
  * stream enum
  */
-enum { ATI_DMA_PLAYBACK, ATI_DMA_CAPTURE, ATI_DMA_SPDIF };
+enum { ATI_DMA_PLAYBACK, ATI_DMA_CAPTURE, ATI_DMA_SPDIF, NUM_ATI_DMAS }; /* DMAs */
+enum { ATI_PCM_OUT, ATI_PCM_IN, ATI_PCM_SPDIF, NUM_ATI_PCMS }; /* AC97 pcm slots */
+enum { ATI_PCMDEV_ANALOG, ATI_PCMDEV_DIGITAL, NUM_ATI_PCMDEVS }; /* pcm devices */
+
+#define NUM_ATI_CODECS	3
+
 
 /*
  * constants and callbacks for each DMA type
@@ -231,6 +237,7 @@
 struct snd_atiixp_dma_ops {
 	int type;			/* ATI_DMA_XXX */
 	unsigned int llp_offset;	/* LINKPTR offset */
+	unsigned int dt_cur;		/* DT_CUR offset */
 	void (*enable_dma)(atiixp_t *chip, int on);	/* called from open callback */
 	void (*enable_transfer)(atiixp_t *chip, int on); /* called from trigger (START/STOP) */
 	void (*flush_dma)(atiixp_t *chip);		/* called from trigger (STOP only) */
@@ -246,9 +253,10 @@
 	snd_pcm_substream_t *substream;	/* assigned PCM substream */
 	unsigned int buf_addr, buf_bytes;	/* DMA buffer address, bytes */
 	unsigned int period_bytes, periods;
+	int opened;
 	int running;
-	struct ac97_pcm *pcm;
 	int pcm_open_flag;
+	int ac97_pcm_type;	/* index # of ac97_pcm to access, -1 = not used */
 };
 
 /*
@@ -264,25 +272,34 @@
 	int irq;
 	
 	ac97_bus_t *ac97_bus;
-	ac97_t *ac97[3];		/* IXP can have up to 3 codecs */
+	ac97_t *ac97[NUM_ATI_CODECS];
 
 	spinlock_t reg_lock;
 	spinlock_t ac97_lock;
 
-	atiixp_dma_t dmas[3];		/* playback, capture, spdif */
+	atiixp_dma_t dmas[NUM_ATI_DMAS];
+	struct ac97_pcm *pcms[NUM_ATI_PCMS];
+	snd_pcm_t *pcmdevs[NUM_ATI_PCMDEVS];
 
 	int max_channels;		/* max. channels for PCM out */
 
 	unsigned int codec_not_ready_bits;	/* for codec detection */
 
 	int spdif_over_aclink;		/* passed from the module option */
+	struct semaphore open_mutex;	/* playback open mutex */
+
+#ifdef CONFIG_PM
+	u32 pci_state[16];
+#endif
 };
 
 
 /*
  */
 static struct pci_device_id snd_atiixp_ids[] = {
-	{ 0x1002, 0x4341, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1002, 0x4341, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
+	{ 0x1002, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB300 */
+	{ 0, }
 };
 
 MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
@@ -393,7 +410,7 @@
 		addr += period_bytes;
 	}
 
-	writel(cpu_to_le32((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN),
+	writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN,
 	       chip->remap_addr + dma->ops->llp_offset);
 
 	dma->period_bytes = period_bytes;
@@ -452,7 +469,9 @@
 			return data >> ATI_REG_PHYS_IN_DATA_SHIFT;
 		udelay(1);
 	} while (--timeout);
-	snd_printk(KERN_WARNING "atiixp: codec read timeout\n");
+	/* time out may happen during reset */
+	if (reg < 0x7c)
+		snd_printk(KERN_WARNING "atiixp: codec read timeout (reg %x)\n", reg);
 	return 0xffff;
 }
 
@@ -527,13 +546,11 @@
 	return 0;
 }
 
-#if 0 /* for P/M */
+#ifdef CONFIG_PM
 static int snd_atiixp_aclink_down(atiixp_t *chip)
 {
-	unsigned long flags;
-
-	if (atiixp_read(chip, MODEM_MIRROR) & ATI_REG_MODEM_MIRROR_RUNNING)
-		return -EBUSY;
+	// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
+	//	return -EBUSY;
 	atiixp_update(chip, CMD,
 		     ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET,
 		     ATI_REG_CMD_POWERDOWN);
@@ -585,12 +602,16 @@
 {
 	unsigned int reg;
 
-	/* enable burst mode */
+	/* set up spdif, enable burst mode */
 	reg = atiixp_read(chip, CMD);
 	reg |= 0x02 << ATI_REG_CMD_SPDF_THRESHOLD_SHIFT;
 	reg |= ATI_REG_CMD_BURST_EN;
 	atiixp_write(chip, CMD, reg);
 
+	reg = atiixp_read(chip, SPDF_CMD);
+	reg &= ~(ATI_REG_SPDF_CMD_LFSR|ATI_REG_SPDF_CMD_SINGLE_CH);
+	atiixp_write(chip, SPDF_CMD, reg);
+
 	/* clear all interrupt source */
 	atiixp_write(chip, ISR, 0xffffffff);
 	/* enable irqs */
@@ -635,7 +656,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->reg_lock, flags);
-	curptr = readl(chip->remap_addr + dma->ops->llp_offset + 12); /* XXX_DMA_DT_CUR */
+	curptr = readl(chip->remap_addr + dma->ops->dt_cur);
 	if (curptr < dma->buf_addr) {
 		snd_printdd("curptr = %x, base = %x\n", curptr, dma->buf_addr);
 		curptr = 0;
@@ -657,7 +678,7 @@
 {
 	if (! dma->substream || ! dma->running)
 		return;
-	snd_printd(KERN_DEBUG "atiixp: XRUN detected (DMA %d)\n", dma->ops->type);
+	snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type);
 	snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
 }
 
@@ -800,15 +821,10 @@
 {
 	unsigned int data;
 	data = atiixp_read(chip, CMD);
-	if (on) {
+	if (on)
 		data |= ATI_REG_CMD_SPDF_OUT_EN;
-		if (chip->spdif_over_aclink)
-			data |= ATI_REG_CMD_SEND_EN;
-	}  else {
+	else
 		data &= ~ATI_REG_CMD_SPDF_OUT_EN;
-		if (chip->spdif_over_aclink)
-			data &= ~ATI_REG_CMD_SEND_EN;
-	}
 	atiixp_write(chip, CMD, data);
 }
 
@@ -835,25 +851,25 @@
 static int snd_atiixp_spdif_prepare(snd_pcm_substream_t *substream)
 {
 	atiixp_t *chip = snd_pcm_substream_chip(substream);
-	unsigned int data;
 
 	spin_lock(&chip->reg_lock);
 	if (chip->spdif_over_aclink) {
+		unsigned int data;
 		/* enable slots 10/11 */
 		atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK,
 			      ATI_REG_CMD_SPDF_CONFIG_01);
-		data = atiixp_read(chip, OUT_DMA_SLOT);
+		data = atiixp_read(chip, OUT_DMA_SLOT) & ~ATI_REG_OUT_DMA_SLOT_MASK;
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
 			ATI_REG_OUT_DMA_SLOT_BIT(11);
 		data |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;
 		atiixp_write(chip, OUT_DMA_SLOT, data);
+		atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_OUT,
+			      substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?
+			      ATI_REG_CMD_INTERLEAVE_OUT : 0);
 	} else {
 		atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, 0);
+		atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF, 0);
 	}
-
-	atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF,
-		      substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?
-		      ATI_REG_CMD_INTERLEAVE_SPDF : 0);
 	spin_unlock(&chip->reg_lock);
 	return 0;
 }
@@ -938,17 +954,18 @@
 	if (err < 0)
 		return err;
 
-	if (dma->pcm) {
+	if (dma->ac97_pcm_type >= 0) {
+		struct ac97_pcm *pcm = chip->pcms[dma->ac97_pcm_type];
 		/* PCM is bound to AC97 codec(s)
 		 * set up the AC97 codecs
 		 */
 		if (dma->pcm_open_flag) {
-			snd_ac97_pcm_close(dma->pcm);
+			snd_ac97_pcm_close(pcm);
 			dma->pcm_open_flag = 0;
 		}
-		err = snd_ac97_pcm_open(dma->pcm, params_rate(hw_params),
+		err = snd_ac97_pcm_open(pcm, params_rate(hw_params),
 					params_channels(hw_params),
-					dma->pcm->r[0].slots);
+					pcm->r[0].slots);
 		if (err >= 0)
 			dma->pcm_open_flag = 1;
 	}
@@ -962,7 +979,8 @@
 	atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data;
 
 	if (dma->pcm_open_flag) {
-		snd_ac97_pcm_close(dma->pcm);
+		struct ac97_pcm *pcm = chip->pcms[dma->ac97_pcm_type];
+		snd_ac97_pcm_close(pcm);
 		dma->pcm_open_flag = 0;
 	}
 	atiixp_clear_dma_packets(chip, dma, substream);
@@ -992,7 +1010,7 @@
 	.periods_max =		ATI_MAX_DESCRIPTORS,
 };
 
-static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma)
+static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma, int pcm_type)
 {
 	atiixp_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
@@ -1001,15 +1019,17 @@
 
 	snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
 
+	if (dma->opened)
+		return -EBUSY;
 	dma->substream = substream;
 	runtime->hw = snd_atiixp_pcm_hw;
-	if (dma->pcm) {
-		runtime->hw.rates = dma->pcm->rates;
+	dma->ac97_pcm_type = pcm_type;
+	if (pcm_type >= 0) {
+		runtime->hw.rates = chip->pcms[pcm_type]->rates;
 		snd_pcm_limit_hw_rates(runtime);
 	} else {
-		/* SPDIF */
-		runtime->hw.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_32000;
-		runtime->hw.rate_min = 32000;
+		/* direct SPDIF */
+		runtime->hw.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
 	}
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
@@ -1019,6 +1039,7 @@
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	dma->ops->enable_dma(chip, 1);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	dma->opened = 1;
 
 	return 0;
 }
@@ -1032,6 +1053,7 @@
 	dma->ops->enable_dma(chip, 0);
 	spin_unlock_irq(&chip->reg_lock);
 	dma->substream = NULL;
+	dma->opened = 0;
 	return 0;
 }
 
@@ -1042,26 +1064,33 @@
 	atiixp_t *chip = snd_pcm_substream_chip(substream);
 	int err;
 
-	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
+	down(&chip->open_mutex);
+	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
+	up(&chip->open_mutex);
+	if (err < 0)
+		return err;
 	substream->runtime->hw.channels_max = chip->max_channels;
 	if (chip->max_channels > 2)
 		/* channels must be even */
 		snd_pcm_hw_constraint_step(substream->runtime, 0,
 					   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
-
 	return 0;
 }
 
 static int snd_atiixp_playback_close(snd_pcm_substream_t *substream)
 {
 	atiixp_t *chip = snd_pcm_substream_chip(substream);
-	return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
+	int err;
+	down(&chip->open_mutex);
+	err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
+	up(&chip->open_mutex);
+	return err;
 }
 
 static int snd_atiixp_capture_open(snd_pcm_substream_t *substream)
 {
 	atiixp_t *chip = snd_pcm_substream_chip(substream);
-	return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE]);
+	return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE], 1);
 }
 
 static int snd_atiixp_capture_close(snd_pcm_substream_t *substream)
@@ -1073,13 +1102,27 @@
 static int snd_atiixp_spdif_open(snd_pcm_substream_t *substream)
 {
 	atiixp_t *chip = snd_pcm_substream_chip(substream);
-	return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF]);
+	int err;
+	down(&chip->open_mutex);
+	if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */
+		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2);
+	else
+		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1);
+	up(&chip->open_mutex);
+	return err;
 }
 
 static int snd_atiixp_spdif_close(snd_pcm_substream_t *substream)
 {
 	atiixp_t *chip = snd_pcm_substream_chip(substream);
-	return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);
+	int err;
+	down(&chip->open_mutex);
+	if (chip->spdif_over_aclink)
+		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
+	else
+		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);
+	up(&chip->open_mutex);
+	return err;
 }
 
 /* AC97 playback */
@@ -1157,6 +1200,7 @@
 static atiixp_dma_ops_t snd_atiixp_playback_dma_ops = {
 	.type = ATI_DMA_PLAYBACK,
 	.llp_offset = ATI_REG_OUT_DMA_LINKPTR,
+	.dt_cur = ATI_REG_OUT_DMA_DT_CUR,
 	.enable_dma = atiixp_out_enable_dma,
 	.enable_transfer = atiixp_out_enable_transfer,
 	.flush_dma = atiixp_out_flush_dma,
@@ -1165,6 +1209,7 @@
 static atiixp_dma_ops_t snd_atiixp_capture_dma_ops = {
 	.type = ATI_DMA_CAPTURE,
 	.llp_offset = ATI_REG_IN_DMA_LINKPTR,
+	.dt_cur = ATI_REG_IN_DMA_DT_CUR,
 	.enable_dma = atiixp_in_enable_dma,
 	.enable_transfer = atiixp_in_enable_transfer,
 	.flush_dma = atiixp_in_flush_dma,
@@ -1173,6 +1218,7 @@
 static atiixp_dma_ops_t snd_atiixp_spdif_dma_ops = {
 	.type = ATI_DMA_SPDIF,
 	.llp_offset = ATI_REG_SPDF_DMA_LINKPTR,
+	.dt_cur = ATI_REG_SPDF_DMA_DT_CUR,
 	.enable_dma = atiixp_spdif_enable_dma,
 	.enable_transfer = atiixp_spdif_enable_transfer,
 	.flush_dma = atiixp_spdif_flush_dma,
@@ -1188,7 +1234,8 @@
 	/* initialize constants */
 	chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops;
 	chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops;
-	chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops;
+	if (! chip->spdif_over_aclink)
+		chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops;
 
 	/* assign AC97 pcm */
 	if (chip->spdif_over_aclink)
@@ -1198,49 +1245,55 @@
 	err = snd_ac97_pcm_assign(pbus, num_pcms, atiixp_pcm_defs);
 	if (err < 0)
 		return err;
+	for (i = 0; i < num_pcms; i++)
+		chip->pcms[i] = &pbus->pcms[i];
 
 	chip->max_channels = 2;
-	if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) {
-		if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE))
+	if (pbus->pcms[ATI_PCM_OUT].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) {
+		if (pbus->pcms[ATI_PCM_OUT].r[0].slots & (1 << AC97_SLOT_LFE))
 			chip->max_channels = 6;
 		else
 			chip->max_channels = 4;
 	}
 
-	chip->dmas[ATI_DMA_PLAYBACK].pcm = &pbus->pcms[0];
-	chip->dmas[ATI_DMA_CAPTURE].pcm = &pbus->pcms[1];
-	if (chip->spdif_over_aclink)
-		chip->dmas[ATI_DMA_SPDIF].pcm = &pbus->pcms[2];
-
 	/* PCM #0: analog I/O */
-	err = snd_pcm_new(chip->card, "ATI IXP AC97", 0, 1, 1, &pcm);
+	err = snd_pcm_new(chip->card, "ATI IXP AC97", ATI_PCMDEV_ANALOG, 1, 1, &pcm);
 	if (err < 0)
 		return err;
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops);
 	pcm->private_data = chip;
 	strcpy(pcm->name, "ATI IXP AC97");
+	chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(chip->pci), 64*1024, 128*1024);
 
 	/* no SPDIF support on codec? */
-	if (chip->dmas[ATI_DMA_SPDIF].pcm && ! chip->dmas[ATI_DMA_SPDIF].pcm->rates)
+	if (chip->pcms[ATI_PCM_SPDIF] && ! chip->pcms[ATI_PCM_SPDIF]->rates)
 		return 0;
 		
+	/* FIXME: non-48k sample rate doesn't work on my test machine with AD1888 */
+	if (chip->pcms[ATI_PCM_SPDIF])
+		chip->pcms[ATI_PCM_SPDIF]->rates = SNDRV_PCM_RATE_48000;
+
 	/* PCM #1: spdif playback */
-	err = snd_pcm_new(chip->card, "ATI IXP IEC958", 1, 1, 0, &pcm);
+	err = snd_pcm_new(chip->card, "ATI IXP IEC958", ATI_PCMDEV_DIGITAL, 1, 0, &pcm);
 	if (err < 0)
 		return err;
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_spdif_ops);
 	pcm->private_data = chip;
-	strcpy(pcm->name, "ATI IXP IEC958");
+	if (chip->spdif_over_aclink)
+		strcpy(pcm->name, "ATI IXP IEC958 (AC97)");
+	else
+		strcpy(pcm->name, "ATI IXP IEC958 (Direct)");
+	chip->pcmdevs[ATI_PCMDEV_DIGITAL] = pcm;
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(chip->pci), 64*1024, 128*1024);
 
 	/* pre-select AC97 SPDIF slots 10/11 */
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < NUM_ATI_CODECS; i++) {
 		if (chip->ac97[i])
 			snd_ac97_update_bits(chip->ac97[i], AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4);
 	}
@@ -1272,10 +1325,12 @@
 		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_CAPTURE]);
 	else if (status & ATI_REG_ISR_IN_STATUS)
 		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]);
-	if (status & ATI_REG_ISR_SPDF_XRUN)
-		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_SPDIF]);
-	else if (status & ATI_REG_ISR_SPDF_STATUS)
-		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_SPDIF]);
+	if (! chip->spdif_over_aclink) {
+		if (status & ATI_REG_ISR_SPDF_XRUN)
+			snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_SPDIF]);
+		else if (status & ATI_REG_ISR_SPDF_STATUS)
+			snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_SPDIF]);
+	}
 
 	/* for codec detection */
 	if (status & CODEC_CHECK_BITS) {
@@ -1303,7 +1358,8 @@
 	ac97_bus_t bus, *pbus;
 	ac97_t ac97;
 	int i, err;
-	static unsigned int codec_skip[3] = {
+	int codec_count;
+	static unsigned int codec_skip[NUM_ATI_CODECS] = {
 		ATI_REG_ISR_CODEC0_NOT_READY,
 		ATI_REG_ISR_CODEC1_NOT_READY,
 		ATI_REG_ISR_CODEC2_NOT_READY,
@@ -1321,15 +1377,34 @@
 		return err;
 	chip->ac97_bus = pbus;
 
-	for (i = 0; i < 3; i++) {
+	codec_count = 0;
+	for (i = 0; i < NUM_ATI_CODECS; i++) {
 		if (chip->codec_not_ready_bits & codec_skip[i])
 			continue;
 		memset(&ac97, 0, sizeof(ac97));
 		ac97.private_data = chip;
 		ac97.pci = chip->pci;
 		ac97.num = i;
-		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0)
-			return err;
+		ac97.scaps = AC97_SCAP_SKIP_MODEM;
+		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
+			if (chip->codec_not_ready_bits)
+				/* codec(s) was detected but not available.
+				 * return the error
+				 */
+				return err;
+			else {
+				/* codec(s) was NOT detected, so just ignore here */
+				chip->ac97[i] = NULL; /* to be sure */
+				snd_printd("atiixp: codec %d not found\n", i);
+				continue;
+			}
+		}
+		codec_count++;
+	}
+
+	if (! codec_count) {
+		snd_printk(KERN_ERR "atiixp: no codec available\n");
+		return -ENODEV;
 	}
 
 	/* snd_ac97_tune_hardware(chip->ac97, ac97_quirks); */
@@ -1338,6 +1413,53 @@
 }
 
 
+#ifdef CONFIG_PM
+/*
+ * power management
+ */
+static int snd_atiixp_suspend(snd_card_t *card, unsigned int state)
+{
+	atiixp_t *chip = snd_magic_cast(atiixp_t, card->pm_private_data, return -EINVAL);
+	int i;
+
+	for (i = 0; i < NUM_ATI_PCMDEVS; i++)
+		if (chip->pcmdevs[i])
+			snd_pcm_suspend_all(chip->pcmdevs[i]);
+	for (i = 0; i < NUM_ATI_CODECS; i++)
+		if (chip->ac97[i])
+			snd_ac97_suspend(chip->ac97[i]);
+	snd_atiixp_aclink_down(chip);
+	snd_atiixp_chip_stop(chip);
+
+	pci_save_state(chip->pci, chip->pci_state);
+	pci_set_power_state(chip->pci, 3);
+	pci_disable_device(chip->pci);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
+}
+
+static int snd_atiixp_resume(snd_card_t *card, unsigned int state)
+{
+	atiixp_t *chip = snd_magic_cast(atiixp_t, card->pm_private_data, return -EINVAL);
+	int i;
+
+	pci_enable_device(chip->pci);
+	pci_restore_state(chip->pci, chip->pci_state);
+	pci_set_power_state(chip->pci, 0);
+
+	snd_atiixp_aclink_reset(chip);
+	snd_atiixp_chip_start(chip);
+
+	for (i = 0; i < NUM_ATI_CODECS; i++)
+		if (chip->ac97[i])
+			snd_ac97_resume(chip->ac97[i]);
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+
 /*
  * proc interface for register dump
  */
@@ -1412,24 +1534,25 @@
 
 	spin_lock_init(&chip->reg_lock);
 	spin_lock_init(&chip->ac97_lock);
+	init_MUTEX(&chip->open_mutex);
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
 	chip->addr = pci_resource_start(pci, 0);
 	if ((chip->res = request_mem_region(chip->addr, ATI_MEM_REGION, "ATI IXP AC97")) == NULL) {
-		snd_printk("unable to grab I/O memory 0x%lx\n", chip->addr);
+		snd_printk(KERN_ERR "unable to grab I/O memory 0x%lx\n", chip->addr);
 		snd_atiixp_free(chip);
 		return -EBUSY;
 	}
 	chip->remap_addr = (unsigned long) ioremap_nocache(chip->addr, ATI_MEM_REGION);
 	if (chip->remap_addr == 0) {
-		snd_printk("AC'97 space ioremap problem\n");
+		snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
 		snd_atiixp_free(chip);
 		return -EIO;
 	}
 
 	if (request_irq(pci->irq, snd_atiixp_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) {
-		snd_printk("unable to grab IRQ %d\n", pci->irq);
+		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
 		snd_atiixp_free(chip);
 		return -EBUSY;
 	}
@@ -1471,7 +1594,7 @@
 
 	pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
 
-	strcpy(card->driver, "ATIIXP");
+	strcpy(card->driver, spdif_aclink[dev] ? "ATIIXP" : "ATIIXP-SPDMA");
 	strcpy(card->shortname, "ATI IXP");
 	if ((err = snd_atiixp_create(card, pci, &chip)) < 0)
 		goto __error;
@@ -1494,10 +1617,12 @@
 	sprintf(card->longname, "%s rev %x at 0x%lx, irq %i",
 		card->shortname, revision, chip->addr, chip->irq);
 
+	snd_card_set_pm_callback(card, snd_atiixp_suspend, snd_atiixp_resume, chip);
+
 	if ((err = snd_card_register(card)) < 0)
 		goto __error;
 
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 
@@ -1508,9 +1633,7 @@
 
 static void __devexit snd_atiixp_remove(struct pci_dev *pci)
 {
-	atiixp_t *chip = snd_magic_cast(atiixp_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -1519,21 +1642,13 @@
 	.id_table = snd_atiixp_ids,
 	.probe = snd_atiixp_probe,
 	.remove = __devexit_p(snd_atiixp_remove),
+	SND_PCI_PM_CALLBACKS
 };
 
 
 static int __init alsa_card_atiixp_init(void)
 {
-	int err;
-
-        if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "ATI IXP AC97 controller not found or device busy\n");
-#endif
-                return err;
-        }
-
-        return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_atiixp_exit(void)
@@ -1543,27 +1658,3 @@
 
 module_init(alsa_card_atiixp_init)
 module_exit(alsa_card_atiixp_exit)
-
-#ifndef MODULE
-
-/* format is: snd-atiixp=enable,index,id,ac97_clock,spdif_aclink */
-
-static int __init alsa_card_atiixp_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 &&
-	       get_option(&str,&ac97_clock[nr_dev]) == 2 &&
-	       get_option(&str,&spdif_aclink[nr_dev]) == 2
-	       );
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-atiixp=", alsa_card_atiixp_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/au88x0/au8810.h	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au8810.h	2004-05-27 18:34:19.000000000 +0100
@@ -7,7 +7,7 @@
 #define CARD_NAME "Aureal Advantage 3D Sound Processor"
 #define CARD_NAME_SHORT "au8810"
 
-#define NR_ADB		0x20
+#define NR_ADB		0x10
 #define NR_WT		0x00
 #define NR_SRC		0x10
 #define NR_A3D		0x10
@@ -51,13 +51,14 @@
 /* ADB */
 #define VORTEX_ADB_SR 0x28400	/* Samplerates enable/disable */
 #define VORTEX_ADB_RTBASE 0x28000
-#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE)
+#define VORTEX_ADB_RTBASE_COUNT 173
 #define VORTEX_ADB_CHNBASE 0x282b4
-#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE)
+#define VORTEX_ADB_CHNBASE_COUNT 24
 #define 	ROUTE_MASK	0xffff
 #define		SOURCE_MASK	0xff00
 #define     ADB_MASK   0xff
 #define		ADB_SHIFT 0x8
+
 /* ADB address */
 #define		OFFSET_ADBDMA	0x00
 #define		OFFSET_SRCIN	0x40
@@ -69,10 +70,12 @@
 #define		OFFSET_SPORTIN	0x78	/* ch 0x13 */
 #define		OFFSET_SPORTOUT	0x90
 #define		OFFSET_SPDIFOUT	0x92	/* ch 0x14 check this! */
-#define		OFFSET_EQIN		0xa0
+#define		OFFSET_EQIN	0xa0
 #define		OFFSET_EQOUT	0x7e	/* 2 routes on ch 0x11 */
 #define		OFFSET_XTALKOUT	0x66	/* crosstalk canceller (source) */
 #define		OFFSET_XTALKIN	0x96	/* crosstalk canceller (sink) */
+#define		OFFSET_A3DIN	0x70	/* ADB sink. */
+#define		OFFSET_A3DOUT	0xA6	/* ADB source. 2 routes per slice = 8 */
 #define		OFFSET_EFXIN	0x80	/* ADB sink. */
 #define		OFFSET_EFXOUT	0x68	/* ADB source. */
 
@@ -89,8 +92,8 @@
 #define ADB_SPDIFOUT(x)	(x + OFFSET_SPDIFOUT)
 #define ADB_EQIN(x) (x + OFFSET_EQIN)
 #define ADB_EQOUT(x) (x + OFFSET_EQOUT)
-#define ADB_A3DOUT(x) (x + 0x50)	/* A3D blocks */
-#define ADB_A3DIN(x) (x + 0x70)
+#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT)	/* 0x10 A3D blocks */
+#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
 #define ADB_XTALKIN(x) (x + OFFSET_XTALKIN)
 #define ADB_XTALKOUT(x) (x + OFFSET_XTALKOUT)
 
@@ -120,20 +123,31 @@
 #define		VOL_MAX 0x7f	/* FIXME: Not confirmed! Just guessed. */
 
 /* SRC */
-#define VORTEX_SRCBLOCK_SR	0x26cc0
-#define VORTEX_SRC_CHNBASE	0x26c40
-#define VORTEX_SRC_RTBASE	0x26c00
-#define VORTEX_SRC_SOURCE	0x26cc4
-#define VORTEX_SRC_SOURCESIZE 0x26cc8
-#define VORTEX_SRC_CONVRATIO 0x26e40
-#define VORTEX_SRC_DRIFT0	0x26e80
-#define VORTEX_SRC_DRIFT1	0x26ec0
-#define VORTEX_SRC_DRIFT2	0x26f40
-#define VORTEX_SRC_U0		0x26e00
-#define VORTEX_SRC_U1		0x26f00
-#define VORTEX_SRC_U2		0x26f80
-#define VORTEX_SRC_DATA		0x26800	/* 0xc800 */
-#define VORTEX_SRC_DATA0	0x26000
+#define VORTEX_SRC_CHNBASE		0x26c40
+#define VORTEX_SRC_RTBASE		0x26c00
+#define VORTEX_SRCBLOCK_SR		0x26cc0
+#define VORTEX_SRC_SOURCE		0x26cc4
+#define VORTEX_SRC_SOURCESIZE	0x26cc8
+/* Params
+	0x26e00	: 1 U0
+	0x26e40	: 2 CR
+	0x26e80	: 3 U3
+	0x26ec0	: 4 DRIFT1
+	0x26f00 : 5 U1
+	0x26f40	: 6 DRIFT2
+	0x26f80	: 7 U2 : Target rate, direction
+*/
+
+#define VORTEX_SRC_CONVRATIO	0x26e40
+#define VORTEX_SRC_DRIFT0		0x26e80
+#define VORTEX_SRC_DRIFT1		0x26ec0
+#define VORTEX_SRC_DRIFT2		0x26f40
+#define VORTEX_SRC_U0			0x26e00
+#define		U0_SLOWLOCK		0x200
+#define VORTEX_SRC_U1			0x26f00
+#define VORTEX_SRC_U2			0x26f80
+#define VORTEX_SRC_DATA			0x26800	/* 0xc800 */
+#define VORTEX_SRC_DATA0		0x26000
 
 /* FIFO */
 #define VORTEX_FIFO_ADBCTRL 0x16100	/* Control bits. */
@@ -150,33 +164,37 @@
 //#define       FIFO_MASK       0x1f    /* at shift left 0xb */
 //#define               FIFO_SIZE       0x20
 #define 	FIFO_BITS	0x03880000
-#define VORTEX_FIFO_ADBDATA 0x14000
-#define VORTEX_FIFO_WTDATA 0x10000
+#define VORTEX_FIFO_ADBDATA	0x14000
+#define VORTEX_FIFO_WTDATA	0x10000
 
 /* CODEC */
-#define VORTEX_CODEC_CTRL 0x29184
-#define VORTEX_CODEC_EN 0x29190
+#define VORTEX_CODEC_CTRL	0x29184
+#define VORTEX_CODEC_EN		0x29190
 #define		EN_CODEC0	0x00000300
+#define 	EN_AC98		0x00000c00 /* Modem AC98 slots. */
 #define		EN_CODEC1	0x00003000
 #define		EN_CODEC	(EN_CODEC0 | EN_CODEC1)
 #define		EN_SPORT	0x00030000
 #define		EN_SPDIF	0x000c0000
-#define VORTEX_CODEC_CHN 0x29080
-#define VORTEX_CODEC_WRITE 0x00800000
-#define VORTEX_CODEC_ADDSHIFT 16
-#define VORTEX_CODEC_ADDMASK 0x7f0000	/* 0x000f0000 */
-#define VORTEX_CODEC_DATSHIFT 0
-#define VORTEX_CODEC_DATMASK 0xffff
-#define VORTEX_CODEC_IO 0x29188
+
+#define VORTEX_CODEC_CHN 	0x29080
+#define VORTEX_CODEC_WRITE	0x00800000
+#define VORTEX_CODEC_ADDSHIFT 	16
+#define VORTEX_CODEC_ADDMASK	0x7f0000	/* 0x000f0000 */
+#define VORTEX_CODEC_DATSHIFT	0
+#define VORTEX_CODEC_DATMASK	0xffff
+#define VORTEX_CODEC_IO		0x29188
 
 /* SPDIF */
-#define VORTEX_SPDIF_FLAGS		0x2205c
-#define VORTEX_SPDIF_CFG0		0x291D0
-#define VORTEX_SPDIF_CFG1		0x291D4
+#define VORTEX_SPDIF_FLAGS	0x2205c
+#define VORTEX_SPDIF_CFG0	0x291D0
+#define VORTEX_SPDIF_CFG1	0x291D4
 #define VORTEX_SPDIF_SMPRATE	0x29194
 
 /* Sample timer */
-#define VORTEX_SMP_TIME  0x29198
+#define VORTEX_SMP_TIME		0x29198
+
+#define VORTEX_MODEM_CTRL	0x291ac
 
 /* IRQ */
 #define VORTEX_IRQ_SOURCE 0x2a000	/* Interrupt source flags. */
@@ -193,19 +211,19 @@
 #define 	CTRL_IRQ_ENABLE	0x00004000
 
 /* write: Timer period config / read: TIMER IRQ ack. */
-#define VORTEX_IRQ_STAT 0x2919c
+#define VORTEX_IRQ_STAT		0x2919c
 
 /* DMA */
-#define VORTEX_ENGINE_CTRL 0x27ae8
-#define 	ENGINE_INIT 0x1380000
+#define VORTEX_ENGINE_CTRL	0x27ae8
+#define 	ENGINE_INIT	0x1380000
 
-		     /* MIDI *//* GAME. */
-#define VORTEX_MIDI_DATA 0x28800
-#define VORTEX_MIDI_CMD 0x28804	/* Write command / Read status */
+/* MIDI *//* GAME. */
+#define VORTEX_MIDI_DATA	0x28800
+#define VORTEX_MIDI_CMD		0x28804	/* Write command / Read status */
 
-#define VORTEX_CTRL2 0x2880c
+#define VORTEX_CTRL2		0x2880c
 #define		CTRL2_GAME_ADCMODE 0x40
-#define VORTEX_GAME_LEGACY 0x28808
-#define VORTEX_GAME_AXIS 0x28810
+#define VORTEX_GAME_LEGACY	0x28808
+#define VORTEX_GAME_AXIS	0x28810
 #define		AXIS_SIZE 4
 #define		AXIS_RANGE 0x1fff
--- diff/sound/pci/au88x0/au8820.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au8820.c	2004-05-27 18:34:19.000000000 +0100
@@ -1,7 +1,7 @@
 #include "au8820.h"
 #include "au88x0.h"
 static struct pci_device_id snd_vortex_ids[] = {
-	{PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX,
+	{PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
 	{0,}
 };
--- diff/sound/pci/au88x0/au8820.h	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au8820.h	2004-05-27 18:34:19.000000000 +0100
@@ -48,9 +48,9 @@
 /* ADB */
 #define VORTEX_ADB_SR 0x10a00	/* Samplerates enable/disable */
 #define VORTEX_ADB_RTBASE 0x10800
-#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE)
+#define VORTEX_ADB_RTBASE_COUNT 103
 #define VORTEX_ADB_CHNBASE 0x1099c
-#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE)
+#define VORTEX_ADB_CHNBASE_COUNT 22
 #define 	ROUTE_MASK	0x3fff
 #define     ADB_MASK   0x7f
 #define		ADB_SHIFT 0x7
--- diff/sound/pci/au88x0/au8830.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au8830.c	2004-05-27 18:34:19.000000000 +0100
@@ -1,7 +1,7 @@
 #include "au8830.h"
 #include "au88x0.h"
 static struct pci_device_id snd_vortex_ids[] = {
-	{PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX2,
+	{PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
 	{0,}
 };
--- diff/sound/pci/au88x0/au8830.h	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au8830.h	2004-05-27 18:34:19.000000000 +0100
@@ -45,7 +45,7 @@
 #define VORTEX_ADBDMA_START 0x27c00	/* Which subbuffer starts */
 
 #define VORTEX_ADBDMA_STATUS 0x27A90	/* stored at AdbDma->this_10 / 2 DWORD in size. */
-/* Starting at MSB, each pair seem to be the current DMA page. */
+/* Starting at the MSB, each pair of bits seem to be the current DMA page. */
 /* This current page bits are consistent (same value) with VORTEX_ADBDMA_STAT) */
 
 /* DMA */
@@ -65,9 +65,9 @@
 /* ADB */
 #define VORTEX_ADB_SR 0x28400	/* Samplerates enable/disable */
 #define VORTEX_ADB_RTBASE 0x28000
-#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE)
+#define VORTEX_ADB_RTBASE_COUNT 173
 #define VORTEX_ADB_CHNBASE 0x282b4
-#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE)
+#define VORTEX_ADB_CHNBASE_COUNT 24
 #define 	ROUTE_MASK	0xffff
 #define		SOURCE_MASK	0xff00
 #define     ADB_MASK   0xff
@@ -147,7 +147,7 @@
 #define VORTEX_SRC_RTBASE		0x26c00
 #define VORTEX_SRCBLOCK_SR		0x26cc0
 #define VORTEX_SRC_SOURCE		0x26cc4
-#define VORTEX_SRC_SOURCESIZE	0x26cc4
+#define VORTEX_SRC_SOURCESIZE	0x26cc8
 /* Params
 	0x26e00	: 1 U0
 	0x26e40	: 2 CR
--- diff/sound/pci/au88x0/au88x0.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au88x0.c	2004-05-27 18:34:19.000000000 +0100
@@ -19,7 +19,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#define SNDRV_GET_ID
+#include <linux/moduleparam.h>
 #include <sound/initval.h>
 
 // module parameters (see "Module Parameters")
@@ -27,17 +27,18 @@
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static int pcifix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 255 };
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(pcifix, "1-255i");
+module_param_array(pcifix, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(pcifix,
 		   SNDRV_ENABLED
@@ -48,80 +49,72 @@
 MODULE_LICENSE("GPL");
 MODULE_DEVICES("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}");
 
-#ifndef MODULE
-/* format is: snd-mychip=enable,index,id */
-static int __init alsa_card_vortex_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-au88x0=", alsa_card_vortex_setup);
-#endif				/* ifndef MODULE */
-
 MODULE_DEVICE_TABLE(pci, snd_vortex_ids);
 
-static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix)
+static void vortex_fix_latency(struct pci_dev *vortex)
 {
-	struct pci_dev *via = NULL;
 	int rc;
-
-	/* autodetect if workarounds are required */
-	while ((via = pci_find_device(PCI_VENDOR_ID_VIA,
-				      PCI_DEVICE_ID_VIA_8365_1, via))) {
-		if (fix == 255) {
+	if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
 			printk(KERN_INFO CARD_NAME
-			       ": detected VIA KT133/KM133. activating workaround...\n");
-			fix = 3;	// do latency and via bridge workaround
-		}
-		break;
+			       ": vortex latency is 0xff\n");
+	} else {
+		printk(KERN_WARNING CARD_NAME
+				": could not set vortex latency: pci error 0x%x\n", rc);
 	}
+}
 
-	/* do not do anything if autodetection was enabled and found no VIA */
-	if (fix == 255)
-		return;
+static void vortex_fix_agp_bridge(struct pci_dev *via)
+{
+	int rc;
+	u8 value;
 
-	/* fix vortex latency */
-	if (fix & 0x01) {
-		if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
-			printk(KERN_INFO CARD_NAME
-			       ": vortex latency is 0xff\n");
-		} else {
-			printk(KERN_WARNING CARD_NAME
-			       ": could not set vortex latency: pci error 0x%x\n",
-			       rc);
-		}
+	/*
+	 * only set the bit (Extend PCI#2 Internal Master for
+	 * Efficient Handling of Dummy Requests) if the can
+	 * read the config and it is not already set
+	 */
+
+	if (!(rc = pci_read_config_byte(via, 0x42, &value))
+			&& ((value & 0x10)
+				|| !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) {
+		printk(KERN_INFO CARD_NAME
+				": bridge config is 0x%x\n", value | 0x10);
+	} else {
+		printk(KERN_WARNING CARD_NAME
+				": could not set vortex latency: pci error 0x%x\n", rc);
 	}
+}
 
-	/* fix via agp bridge */
-	if (via && (fix & 0x02)) {
-		u8 value;
-
-		/*
-		 * only set the bit (Extend PCI#2 Internal Master for
-		 * Efficient Handling of Dummy Requests) if the can
-		 * read the config and it is not already set
-		 */
-
-		if (!(rc = pci_read_config_byte(via, 0x42, &value))
-		    && ((value & 0x10)
-			|| !(rc =
-			     pci_write_config_byte(via, 0x42, value | 0x10)))) {
+static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix)
+{
+	struct pci_dev *via;
 
-			printk(KERN_INFO CARD_NAME
-			       ": bridge config is 0x%x\n", value | 0x10);
-		} else {
-			printk(KERN_WARNING CARD_NAME
-			       ": could not set vortex latency: pci error 0x%x\n",
-			       rc);
+	/* autodetect if workarounds are required */
+	if (fix == 255) {
+		/* VIA KT133 */
+		via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8365_1, NULL);
+		/* VIA Apollo */
+		if (via == NULL) {
+			via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, NULL);
+		}
+		/* AMD Irongate */
+		if (via == NULL) {
+			via = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL);
 		}
+		if (via) {
+			printk(KERN_INFO CARD_NAME ": Activating latency workaround...\n");
+			vortex_fix_latency(vortex);
+			vortex_fix_agp_bridge(via);
+		}
+	} else {
+		if (fix & 0x1)
+			vortex_fix_latency(vortex);
+		if ((fix & 0x2) && (via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8365_1, NULL)))
+			vortex_fix_agp_bridge(via);
+		if ((fix & 0x4) && (via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, NULL)))
+			vortex_fix_agp_bridge(via);
+		if ((fix & 0x8) && (via = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL)))
+			vortex_fix_agp_bridge(via);
 	}
 }
 
@@ -370,7 +363,7 @@
 		return err;
 	}
 	// (7)
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	vortex_connect_default(chip, 1);
 	vortex_enable_int(chip);
@@ -380,16 +373,8 @@
 // destructor -- see "Destructor" sub-section
 static void __devexit snd_vortex_remove(struct pci_dev *pci)
 {
-	vortex_t *vortex = snd_magic_cast(vortex_t,
-					  pci_get_drvdata(pci), return);
-
-	if (vortex) {
-		// Release ALSA stuff.
-		snd_card_free(vortex->card);
-		// Free Vortex struct.
-		pci_set_drvdata(pci, NULL);
-	} else
-		printk("snd_vortex_remove called more than one time!\n");
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
 }
 
 // pci_driver definition
@@ -403,16 +388,7 @@
 // initialization of the module
 static int __init alsa_card_vortex_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Aureal soundcard not found "
-		       "or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 // clean up the module
--- diff/sound/pci/au88x0/au88x0.h	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au88x0.h	2004-05-27 18:34:19.000000000 +0100
@@ -17,6 +17,7 @@
 #ifndef __SOUND_AU88X0_H
 #define __SOUND_AU88X0_H
 
+#ifdef __KERNEL__
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -28,6 +29,8 @@
 #include <sound/hwdep.h>
 #include <sound/ac97_codec.h>
 
+#endif
+
 #ifndef CHIP_AU8820
 #include "au88x0_eq.h"
 #include "au88x0_a3d.h"
@@ -69,20 +72,19 @@
 #define IRQ_MODEM	0x4000
 
 /* ADB Resource */
-#define VORTEX_RESOURCE_DMA		0x00000000
-#define VORTEX_RESOURCE_SRC		0x00000001
+#define VORTEX_RESOURCE_DMA	0x00000000
+#define VORTEX_RESOURCE_SRC	0x00000001
 #define VORTEX_RESOURCE_MIXIN	0x00000002
 #define VORTEX_RESOURCE_MIXOUT	0x00000003
-#define VORTEX_RESOURCE_A3D		0x00000004
+#define VORTEX_RESOURCE_A3D	0x00000004
 #define VORTEX_RESOURCE_LAST	0x00000005
 
 /* Check for SDAC bit in "Extended audio ID" AC97 register */
-#define VORTEX_IS_QUAD(x) ((x->codec == NULL) ?  0 : (x->codec->ext_id|0x80))
+#define VORTEX_IS_QUAD(x) ((x->codec == NULL) ?  0 : (x->codec->ext_id&0x80))
 /* Check if chip has bug. */
 #define IS_BAD_CHIP(x) (\
-	(x->rev < 3 && x->device == PCI_DEVICE_ID_AUREAL_VORTEX) || \
-	(x->rev < 0xfe && x->device == PCI_DEVICE_ID_AUREAL_VORTEX2) || \
-	(x->rev < 0xfe && x->device == PCI_DEVICE_ID_AUREAL_ADVANTAGE))
+	(x->rev == 0xfe && x->device == PCI_DEVICE_ID_AUREAL_VORTEX_2) || \
+	(x->rev == 0xfe && x->device == PCI_DEVICE_ID_AUREAL_ADVANTAGE))
 
 
 /* PCM devices */
--- diff/sound/pci/au88x0/au88x0_a3d.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au88x0_a3d.c	2004-05-27 18:34:19.000000000 +0100
@@ -617,6 +617,12 @@
 static void vortex_Vort3D_connect(vortex_t * v, int en)
 {
 	int i;
+	
+// Disable AU8810 routes, since they seem to be wrong (in au8810.h).
+#ifdef CHIP_AU8810
+	return;
+#endif
+	
 #if 1
 	/* Alloc Xtalk mixin resources */
 	v->mixxtlk[0] =
--- diff/sound/pci/au88x0/au88x0_core.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au88x0_core.c	2004-05-27 18:34:19.000000000 +0100
@@ -72,6 +72,7 @@
             into au88x0_pcm.c .
  06-06-2003 Buffer shifter bugfix. Mixer volume fix.
  07-12-2003 A3D routing finally fixed. Believed to be OK.
+ 25-03-2004 Many thanks to Claudia, for such valuable bug reports.
  
 */
 
@@ -772,7 +773,9 @@
 	return 1;
 }
 
- /*FIFO*/ static void
+ /*FIFO*/ 
+
+static void
 vortex_fifo_clearadbdata(vortex_t * vortex, int fifo, int x)
 {
 	for (x--; x >= 0; x--)
@@ -1345,31 +1348,29 @@
 	dma->nr_periods = count;
 	dma->sgbuf = sgbuf;
 
-	psize--;
-
 	dma->cfg0 = 0;
 	dma->cfg1 = 0;
 	switch (count) {
 		/* Four or more pages */
 	default:
 	case 4:
-		dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | psize;
-		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
+		dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
+		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
 			snd_sgbuf_get_addr(sgbuf, psize * 3));
 		/* 3 pages */
 	case 3:
 		dma->cfg0 |= 0x12000000;
-		dma->cfg1 |= 0x80000000 | 0x40000000 | (psize << 0xc);
-		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
+		dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
+		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4)  + 0x8,
 			snd_sgbuf_get_addr(sgbuf, psize * 2));
 		/* 2 pages */
 	case 2:
-		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | psize;
-		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
+		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
+		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
 			snd_sgbuf_get_addr(sgbuf, psize));
 		/* 1 page */
 	case 1:
-		dma->cfg0 |= 0x80000000 | 0x40000000 | (psize << 0xc);
+		dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
 			snd_sgbuf_get_addr(sgbuf, 0));
 		break;
@@ -1575,11 +1576,11 @@
 	/* it looks like we are writing more than we need to...
 	 * if we write what we are supposed to it breaks things... */
 	hwwrite(vortex->mmio, VORTEX_ADB_SR, 0);
-	for (i = 0; i < VORTEX_ADB_RTBASE_SIZE; i++)
+	for (i = 0; i < VORTEX_ADB_RTBASE_COUNT; i++)
 		hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (i << 2),
 			hwread(vortex->mmio,
 			       VORTEX_ADB_RTBASE + (i << 2)) | ROUTE_MASK);
-	for (i = 0; i < VORTEX_ADB_CHNBASE_SIZE; i++) {
+	for (i = 0; i < VORTEX_ADB_CHNBASE_COUNT; i++) {
 		hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (i << 2),
 			hwread(vortex->mmio,
 			       VORTEX_ADB_CHNBASE + (i << 2)) | ROUTE_MASK);
@@ -1922,6 +1923,9 @@
 	// Connect front channels through EQ.
 	vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_EQIN(0));
 	vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_EQIN(1));
+	/* Lower volume, since EQ has some gain. */
+	vortex_mix_setvolumebyte(vortex, mixers[0], 0);
+	vortex_mix_setvolumebyte(vortex, mixers[1], 0);
 	vortex_route(vortex, en, 0x11, ADB_EQOUT(0), ADB_CODECOUT(0));
 	vortex_route(vortex, en, 0x11, ADB_EQOUT(1), ADB_CODECOUT(1));
 
@@ -2007,9 +2011,11 @@
 }
 
 /* Default Connections  */
+static int
+vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type);
+
 static void vortex_connect_default(vortex_t * vortex, int en)
 {
-	// FIXME: check if checkout was succesful.
 	// Connect AC97 codec.
 	vortex->mixplayb[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
 				  VORTEX_RESOURCE_MIXOUT);
@@ -2044,7 +2050,7 @@
 #ifndef CHIP_AU8810
 	vortex_wt_connect(vortex, en);
 #endif
-	// A3D (crosstalk canceler and A3D slices).
+	// A3D (crosstalk canceler and A3D slices). AU8810 disabled for now.
 #ifndef CHIP_AU8820
 	vortex_Vort3D_connect(vortex, en);
 #endif
@@ -2053,18 +2059,7 @@
 	// Connect DSP interface for SQ3500 turbo (not here i think...)
 
 	// Connect AC98 modem codec
- 	
- 	/* Fast Play Workaround. Revision 0xFE does not seem to need it. */
- 	printk(KERN_INFO "vortex: revision = 0x%x, device = %d\n", vortex->rev, vortex->device);
- 	if (IS_BAD_CHIP(vortex)) {
- 		printk(KERN_INFO "vortex: Erratum workaround enabled.\n");
- #ifndef CHIP_AU8820
- 		vortex->fixed_res[VORTEX_RESOURCE_DMA] = 0x00000001;
- #endif
- 		// Channel swapping workaround. We are nuking registers somewhere, or
- 		// its a hardware bug.
- 		vortex->fixed_res[VORTEX_RESOURCE_SRC] = 0x00000001;
- 	}
+	
 }
 
 /*
@@ -2081,7 +2076,7 @@
 {
 	stream_t *stream;
 	int i, en;
-
+	
 	if ((nr_ch == 3)
 	    || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2)))
 		return -EBUSY;
@@ -2105,7 +2100,6 @@
 	stream->dir = dir;
 	stream->type = type;
 
-	// FIXME: check for success of checkout or checkin.
 	/* PLAYBACK ROUTES. */
 	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
 		int src[4], mix[4], ch_top;
@@ -2165,8 +2159,7 @@
 		for (i = 0; i < nr_ch; i++) {
 			if (stream->type == VORTEX_PCM_ADB) {
 				vortex_connection_adbdma_src(vortex, en,
-							     src[nr_ch - 1], 
-							     //src[0], 
+							     src[nr_ch - 1],
 							     dma,
 							     src[i]);
 				vortex_connection_src_mixin(vortex, en,
@@ -2188,7 +2181,7 @@
 #ifndef CHIP_AU8820
 			if (stream->type == VORTEX_PCM_A3D) {
 				vortex_connection_adbdma_src(vortex, en,
-							     src[0], 
+							     src[nr_ch - 1], 
 								 dma,
 							     src[i]);
 				vortex_route(vortex, en, 0x11, ADB_SRCOUT(src[i]), ADB_A3DIN(a3d));
@@ -2237,7 +2230,7 @@
 				     ADB_SPDIFOUT(1));
 		}
 #endif
-		/* CAPTURE ROUTES. */
+	/* CAPTURE ROUTES. */
 	} else {
 		int src[2], mix[2];
 
@@ -2271,7 +2264,7 @@
 			vortex_connection_mixin_mix(vortex, en,
 						    MIX_CAPT(1), mix[0], 0);
 			vortex_connection_src_adbdma(vortex, en,
-						     src[nr_ch - 1],
+						     src[0],
 						     src[0], dma);
 		} else {
 			vortex_connection_mixin_mix(vortex, en,
@@ -2279,7 +2272,7 @@
 			vortex_connection_mix_src(vortex, en, 0x11, mix[1],
 						  src[1]);
 			vortex_connection_src_src_adbdma(vortex, en,
-							 src[0], src[0],
+							 src[1], src[0],
 							 src[1], dma);
 		}
 	}
--- diff/sound/pci/au88x0/au88x0_eq.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au88x0_eq.c	2004-05-27 18:34:19.000000000 +0100
@@ -710,11 +710,13 @@
 static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp)
 {
 	eqlzr_t *eq = &(vortex->eq);
-
+	
 	if ((eq->this28) && (bp == 0)) {
+		/* EQ enabled */
 		vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
 		vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
 	} else {
+		/* EQ disabled. */
 		vortex_EqHw_SetLeftGainsTarget(vortex, (u16 *) (eq->this14));
 		vortex_EqHw_SetRightGainsTarget(vortex, (u16 *) (eq->this14));
 		vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
--- diff/sound/pci/au88x0/au88x0_game.c	2004-05-27 13:41:27.000000000 +0100
+++ source/sound/pci/au88x0/au88x0_game.c	2004-05-27 18:34:19.000000000 +0100
@@ -42,8 +42,6 @@
 
 #define VORTEX_GAME_DWAIT	20	/* 20 ms */
 
-static struct gameport gameport;
-
 static unsigned char vortex_game_read(struct gameport *gameport)
 {
 	vortex_t *vortex = gameport->driver;
@@ -98,8 +96,10 @@
 
 static int vortex_gameport_register(vortex_t * vortex)
 {
-	vortex->gameport = &gameport;
-
+	if ((vortex->gameport = snd_kcalloc(sizeof(struct gameport), GFP_KERNEL)) == NULL) {
+		return -1;
+	};
+	
 	vortex->gameport->driver = vortex;
 	vortex->gameport->fuzz = 64;
 
@@ -118,8 +118,10 @@
 
 static int vortex_gameport_unregister(vortex_t * vortex)
 {
-	if (vortex->gameport != NULL)
+	if (vortex->gameport != NULL) {
 		gameport_unregister_port(vortex->gameport);
+		kfree(vortex->gameport);
+	}
 	return 0;
 }
 
--- diff/sound/pci/au88x0/au88x0_pcm.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au88x0_pcm.c	2004-05-27 18:34:19.000000000 +0100
@@ -18,8 +18,7 @@
  * Vortex PCM ALSA driver.
  *
  * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet.
- * It remains stuck,and DMA transfers do not happen.
- *
+ * It remains stuck,and DMA transfers do not happen. 
  */
 
 #include <sound/driver.h>
@@ -124,7 +123,7 @@
 	vortex_t *vortex = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	int err;
-
+	
 	/* Force equal size periods */
 	if ((err =
 	     snd_pcm_hw_constraint_integer(runtime,
@@ -232,12 +231,13 @@
 	}
 #ifndef CHIP_AU8810
 	else {
-		/*if (stream != NULL)
+		/* if (stream != NULL)
 		   vortex_wt_allocroute(chip, substream->number, 0); */
 		vortex_wt_allocroute(chip, substream->number,
 				     params_channels(hw_params));
 		stream = substream->runtime->private_data =
 		    &chip->dma_wt[substream->number];
+		stream->dma = substream->number;
 		stream->substream = substream;
 		vortex_wtdma_setbuffers(chip, substream->number, sgbuf,
 					params_period_bytes(hw_params),
@@ -325,7 +325,7 @@
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		// do something to stop the PCM engine
-		//printk(KERN_INFO "vortex: stop %d\n", dma)
+		//printk(KERN_INFO "vortex: stop %d\n", dma);
 		stream->fifo_enabled = 0;
 		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
 			vortex_adbdma_pausefifo(chip, dma);
@@ -502,18 +502,13 @@
 	if (idx == VORTEX_PCM_ADB)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 				&snd_vortex_playback_ops);
-
+	
 	/* pre-allocation of Scatter-Gather buffers */
 	
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-										  snd_dma_pci_data(chip->pci_dev),
-										  0x10000, 0x10000);
-	
-	// The above should be used, as soon as ALSA gets updated.
-	/*
-	snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci_dev, pcm,
-						 0x10000, 0x10000);
-	*/
+					      snd_dma_pci_data(chip->pci_dev),
+					      0x10000, 0x10000);
+
 	if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
 		snd_kcontrol_t *kcontrol;
 
--- diff/sound/pci/au88x0/au88x0_synth.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/au88x0/au88x0_synth.c	2004-05-27 18:34:19.000000000 +0100
@@ -36,6 +36,7 @@
 
 /* WT */
 
+/* Put 2 WT channels together for one stereo interlaced channel. */
 static void vortex_wt_setstereo(vortex_t * vortex, u32 wt, u32 stereo)
 {
 	int temp;
@@ -47,6 +48,7 @@
 	hwwrite(vortex->mmio, WT_STEREO(wt), temp);
 }
 
+/* Join to mixdown route. */
 static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en)
 {
 	int temp;
@@ -60,7 +62,7 @@
 	hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp);
 }
 
-// WT routing is still a mistery.
+/* Setup WT route. */
 static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
 {
 	wt_voice_t *voice = &(vortex->wt_voice[wt]);
@@ -68,13 +70,15 @@
 
 	//FIXME: WT audio routing.
 	if (nr_ch) {
-		vortex_fifo_wtinitialize(vortex, wt, 2);
+		vortex_fifo_wtinitialize(vortex, wt, 1);
 		vortex_fifo_setwtvalid(vortex, wt, 1);
 		vortex_wt_setstereo(vortex, wt, nr_ch - 1);
 	} else
 		vortex_fifo_setwtvalid(vortex, wt, 0);
-
-	vortex_wt_setdsout(vortex, wt, 0);
+	
+	/* Set mixdown mode. */
+	vortex_wt_setdsout(vortex, wt, 1);
+	/* Set other parameter registers. */
 	hwwrite(vortex->mmio, WT_SRAMP(0), 0x880000);
 	//hwwrite(vortex->mmio, WT_GMODE(0), 0xffffffff);
 #ifdef CHIP_AU8830
@@ -87,7 +91,7 @@
 
 	temp = hwread(vortex->mmio, WT_PARM(wt, 3));
 	printk("vortex: WT PARM3: %x\n", temp);
-	hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
+	//hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
 
 	hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
 	hwwrite(vortex->mmio, WT_DELAY(wt, 1), 0);
@@ -106,6 +110,7 @@
 	return 0;
 }
 
+
 static void vortex_wt_connect(vortex_t * vortex, int en)
 {
 	int i, ii, mix;
@@ -129,15 +134,12 @@
 				     ADB_WTOUT(i, ii + 0x20), ADB_MIXIN(mix));
 
 			vortex_connection_mixin_mix(vortex, en, mix,
-						    vortex->mixplayb[ii %
-								     2], 0);
+						    vortex->mixplayb[ii % 2], 0);
 			if (VORTEX_IS_QUAD(vortex))
 				vortex_connection_mixin_mix(vortex, en,
 							    mix,
-							    vortex->
-							    mixplayb[2 +
-								     (ii %
-								      2)], 0);
+							    vortex->mixplayb[2 +
+								     (ii % 2)], 0);
 		}
 	}
 	for (i = 0; i < NR_WT; i++) {
--- diff/sound/pci/azt3328.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/azt3328.c	2004-05-27 18:34:20.000000000 +0100
@@ -98,13 +98,13 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include "azt3328.h"
 
@@ -166,18 +166,19 @@
 #ifdef SUPPORT_JOYSTICK
 static int joystick[SNDRV_CARDS];
 #endif
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for AZF3328 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC);
 #ifdef SUPPORT_JOYSTICK
-MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick, bool, boot_devs, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard.");
 MODULE_PARM_SYNTAX(joystick, SNDRV_BOOLEAN_FALSE_DESC);
 #endif
@@ -1267,6 +1268,10 @@
         if (chip->irq < 0)
                 goto __end_hw;
 
+	/* reset (close) mixer */
+	snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */
+	snd_azf3328_mixer_write(chip, IDX_MIXER_RESET, 0x0, WORD_VALUE);
+
         /* interrupt setup - mask everything */
 	/* FIXME */
 
@@ -1540,7 +1545,7 @@
 	snd_azf3328_config_joystick(chip, joystick[dev]);
 #endif
 
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 
 	snd_azf3328_dbgcallleave();
@@ -1549,16 +1554,8 @@
 
 static void __devexit snd_azf3328_remove(struct pci_dev *pci)
 {
-        azf3328_t *chip = snd_magic_cast(azf3328_t, pci_get_drvdata(pci), return);
-	
 	snd_azf3328_dbgcallenter();
-
-	/* reset (close) mixer */
-	snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */
-	snd_azf3328_mixer_write(chip, IDX_MIXER_RESET, 0x0, WORD_VALUE);
-
-        if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 	snd_azf3328_dbgcallleave();
 }
@@ -1573,18 +1570,10 @@
 static int __init alsa_card_azf3328_init(void)
 {
 	int err;
-	
 	snd_azf3328_dbgcallenter();
-
-	if ((err = pci_module_init(&driver)) < 0)
-	{
-#ifdef MODULE
-		printk(KERN_ERR "azt3328: no AZF3328 based soundcards found or device busy\n");
-#endif
-		return err;
-	}
+	err = pci_module_init(&driver);
 	snd_azf3328_dbgcallleave();
-	return 0;
+	return err;
 }
 
 static void __exit alsa_card_azf3328_exit(void)
@@ -1596,31 +1585,3 @@
 
 module_init(alsa_card_azf3328_init)
 module_exit(alsa_card_azf3328_exit)
-
-#ifndef MODULE
-
-/* format is: snd-azf3328=enable,index,id,joystick */
-
-static int __init alsa_card_azf3328_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	snd_azf3328_dbgcallenter();
-
-	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
-#ifdef SUPPORT_JOYSTICK
-	       && get_option(&str,&joystick[nr_dev]) == 2
-#endif
-	       );
-	nr_dev++;
-	snd_azf3328_dbgcallleave();
-	return 1;
-}
-
-__setup("snd-azt3328=", alsa_card_azf3328_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/bt87x.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/bt87x.c	2004-05-27 18:34:20.000000000 +0100
@@ -26,13 +26,13 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/control.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
@@ -46,17 +46,18 @@
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int digital_rate[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* digital input rate */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Bt87x soundcard");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Bt87x soundcard");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Bt87x soundcard");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(digital_rate, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(digital_rate, int, boot_devs, 0444);
 MODULE_PARM_DESC(digital_rate, "Digital input rate for Bt87x soundcard");
 MODULE_PARM_SYNTAX(digital_rate, SNDRV_ENABLED);
 
@@ -808,7 +809,7 @@
 	if (err < 0)
 		goto _error;
 
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	++dev;
 	return 0;
 
@@ -819,9 +820,7 @@
 
 static void __devexit snd_bt87x_remove(struct pci_dev *pci)
 {
-	bt87x_t *chip = snd_magic_cast(bt87x_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -851,16 +850,7 @@
 
 static int __init alsa_card_bt87x_init(void)
 {
-	int err;
-
-	err = pci_module_init(&driver);
-	if (err < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Bt87x soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_bt87x_exit(void)
@@ -870,24 +860,3 @@
 
 module_init(alsa_card_bt87x_init)
 module_exit(alsa_card_bt87x_exit)
-
-#ifndef MODULE
-
-/* format is: snd-bt87x=enable,index,id */
-
-static int __init alsa_card_bt87x_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-bt87x=", alsa_card_bt87x_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/cmipci.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/cmipci.c	2004-05-27 18:34:20.000000000 +0100
@@ -20,10 +20,6 @@
 /* Does not work. Warning may block system in capture mode */
 /* #define USE_VAR48KRATE */
 
-/* Define this if you want soft ac3 encoding */
-#define DO_SOFT_AC3
-#define USE_AES_IEC958
-
 #include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
@@ -32,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -41,7 +38,6 @@
 #include <sound/opl3.h>
 #include <sound/sb.h>
 #include <sound/asoundef.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
@@ -62,35 +58,31 @@
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable switches */
 static long mpu_port[SNDRV_CARDS];
 static long fm_port[SNDRV_CARDS];
-#ifdef DO_SOFT_AC3
 static int soft_ac3[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)]=1};
-#endif
 #ifdef SUPPORT_JOYSTICK
 static int joystick_port[SNDRV_CARDS];
 #endif
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for C-Media PCI soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for C-Media PCI soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable C-Media PCI soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x320},{0x310},{0x300}},dialog:list");
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM port.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0},{0x388},{0x3c8},{0x3e0},{0x3e8}},dialog:list");
-#ifdef DO_SOFT_AC3
-MODULE_PARM(soft_ac3, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(soft_ac3, bool, boot_devs, 0444);
 MODULE_PARM_DESC(soft_ac3, "Sofware-conversion of raw SPDIF packets (model 033 only).");
-MODULE_PARM_SYNTAX(soft_ac3, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
-#endif
 #ifdef SUPPORT_JOYSTICK
-MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick_port, int, boot_devs, 0444);
 MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{1},{0x200},{0x201}},dialog:list");
 #endif
@@ -426,7 +418,6 @@
 	unsigned int is_dac;		/* is dac? */
 	int bytes_per_frame;
 	int shift;
-	int ac3_shift;	/* extra shift: 1 on soft ac3 mode */
 };
 
 /* mixer elements toggled/resumed during ac3 playback */
@@ -472,10 +463,6 @@
 
 	unsigned int dig_status;
 	unsigned int dig_pcm_status;
-#ifdef USE_AES_IEC958
-	snd_ctl_elem_value_t *spdif_channel;
-#endif
-	snd_kcontrol_t *spdif_pcm_ctl;
 
 	snd_pcm_hardware_t *hw_info[3]; /* for playbacks */
 
@@ -784,8 +771,6 @@
 	/* buffer and period sizes in frame */
 	rec->dma_size = runtime->buffer_size << rec->shift;
 	rec->period_size = runtime->period_size << rec->shift;
-	rec->dma_size <<= rec->ac3_shift;
-	rec->period_size <<= rec->ac3_shift;
 	if (runtime->channels > 2) {
 		/* multi-channels */
 		rec->dma_size = (rec->dma_size * runtime->channels) / 2;
@@ -911,7 +896,6 @@
 	ptr = snd_cmipci_read(cm, reg) - rec->offset;
 	ptr = bytes_to_frames(substream->runtime, ptr);
 #endif
-	ptr >>= rec->ac3_shift;
 	if (substream->runtime->channels > 2)
 		ptr = (ptr * 2) / substream->runtime->channels;
 	return ptr;
@@ -953,358 +937,6 @@
 	return snd_cmipci_pcm_pointer(cm, &cm->channel[CM_CH_CAPT], substream);
 }
 
-#ifdef DO_SOFT_AC3
-/*
- * special tricks for soft ac3 transfer:
- *
- * we compose an iec958 subframe from 16bit ac3 sample and
- * write the raw subframe via 32bit data mode.
- */
-
-# ifndef USE_AES_IEC958
-
-/* find parity for bit 4~30 */
-static unsigned int parity(unsigned int data)
-{
-	unsigned int parity = 0;
-	int counter = 4;
-
-	data >>= 4;	/* start from bit 4 */
-	while (counter <= 30) {
-		if (data & 1)
-			parity++;
-		data >>= 1;
-		counter++;
-	}
-	return parity & 1;
-}
-
-/*
- * compose 32bit iec958 subframe with non-audio data.
- * bit 0-3  = preamble
- *     4-7  = aux (=0)
- *     8-27 = data (12-27 for 16bit)
- *     28   = validity (=0)
- *     29   = user data (=0)
- *     30   = channel status
- *     31   = parity
- *
- * channel status is assumed as consumer, non-audio
- * thus all 0 except bit 1
- */
-inline static u32 convert_ac3_32bit(cmipci_t *cm, u32 val)
-{
-	u32 data = (u32)val << 12;
-
-	if (cm->spdif_counter == 2 || cm->spdif_counter == 3) /* bit 1 */
-		data |= 0x40000000;	/* indicate AC-3 raw data */
-	if (parity(data))		/* parity bit 4-30 */
-		data |= 0x80000000;
-	if (cm->spdif_counter == 0)
-		data |= 3;		/* preamble 'M' */
-	else if (cm->spdif_counter & 1)
-		data |= 5;		/* odd, 'W' */
-	else
-		data |= 9;		/* even, 'M' */
-
-	cm->spdif_counter++;
-	if (cm->spdif_counter == 384)
-		cm->spdif_counter = 0;
-
-	return data;
-}
-
-# else  /* if USE_AES_IEC958 */
-
-/*
- * The bitstream handling
- */
-typedef struct iec958_stru_bitstream {
-	u32 *data;		/* Holds the current position */
-	u32  left;		/* Bits left in current 32bit frame */
-	u32  word;		/* The 32bit frame of the current position */
-	u32  bits;		/* All bits together */
-	int   err;		/* Error condition */
-} iec958_bitstream_t ;
-
-static iec958_bitstream_t bs;
-
-/* Initialize ptr on the buffer */
-static void iec958_init_bitstream(u8 *buf, u32 size)
-{
-	bs.data = (u32 *)buf;		/* Set initial position */
-	bs.word = *bs.data;		/* The first 32bit frame */
-	bs.left = 32;			/* has exactly 32bits */
-	bs.bits = size;
-	bs.err = 0;
-}
-
-/* Remove ptr on the buffer */
-static void iec958_clear_bitstream(void)
-{
-	bs.data = NULL;
-	bs.left = 0;
-	bs.err = 0;
-}
-
-/* Get bits from bitstream (max 32) */
-static inline u32 iec958_getbits(u32 bits)
-{
-	u32 res;
-
-	if (bs.bits < bits) {
-		bits = bs.bits;
-		bs.err = 1;
-	}
-	if (bits > 32) {
-		bits = 32;
-		bs.err = 1;
-	}
-	bs.bits -= bits;
-
-#  ifdef WORDS_BIGENDIAN
-	if (bits < bs.left) {		/* Within 32bit frame */
-		res = (bs.word << (32 - bs.left)) >> (32 - bits);
-		bs.left -= bits;
-		goto out;
-	}				/* We may cross the frame boundary */
-	res   = (bs.word << (32 - bs.left)) >> (32 - bs.left);
-	bits -= bs.left;
-
-	bs.word = *(++bs.data);		/* Next 32bit frame */
-
-	if (bits)			/* Add remaining bits, if any */
-		res = (res << bits) | (bs.word >> (32 - bits));
-
-#  else  /* not WORDS_BIGENDIAN */
-
-	if (bits < bs.left) {		/* Within 32bit frame */
-		res = (bs.word << (32 - bits)) >> (32 - bits);
-		bs.word >>= bits;
-		bs.left -= bits;
-		goto out;
-	}				/* We may cross the frame boundary */
-	res   = bs.word;
-	bits -= bs.left;
-
-	bs.word = *(++bs.data);		/* Next 32bit frame */
-
-	if (bits) {			/* Add remaining bits, if any */
-		res = res | (((bs.word << (32 - bits)) >> (32 - bits)) << bits);
-		bs.word >>= bits;
-	}
-#  endif /* not WORDS_BIGENDIAN */
-
-	bs.left = (32 - bits);
-out:
-	return res;
-}
-
-static inline u32 iec958_bits_avail(void)
-{
-	return bs.bits;
-}
-
-static inline int iec958_error(void)
-{
-	return bs.err;
-}
-
-/*
- * Determine parity for time slots 4 upto 30
- * to be sure that bit 4 upt 31 will carry
- * an even number of ones and zeros.
- */
-static u32 iec958_parity(u32 data)
-{
-	u32 parity = 0;
-	int counter = 4;
-
-	data >>= 4;     /* start from bit 4 */
-	while (counter++ <= 30) {
-		if (data & 0x00000001)
-			parity++;
-		data >>= 1;
-	}
-	return (parity & 0x00000001);
-}
-
-/*
- * Compose 32bit iec958 subframe, two sub frames
- * build one frame with two channels.
- *
- * bit 0-3  = preamble
- *     4-7  = AUX (=0)
- *     8-27 = data (12-27 for 16bit, 8-27 for 20bit, and 24bit without AUX)
- *     28   = validity (0 for valid data, else 'in error')
- *     29   = user data (0)
- *     30   = channel status (24 bytes for 192 frames)
- *     31   = parity
- */
-
-static inline u32 iec958_subframe(cmipci_t *cm, snd_ctl_elem_value_t * ucontrol)
-{
-	u32 data;
-	u32 byte = cm->spdif_counter >> 4;
-	u32 mask = 1 << ((cm->spdif_counter >> 1) - (byte << 3));
-	u8 * status = ucontrol->value.iec958.status;
-
-	if (status[2] & IEC958_AES2_PRO_SBITS_24) {
-		/* Does this work for LE systems ??? */
-		if (status[2] & IEC958_AES2_PRO_WORDLEN_24_20) {
-			data = iec958_getbits(24);
-			data <<= 4;
-		} else {
-			data = iec958_getbits(20);
-			data <<= 8;
-		}
-	} else {
-		if (status[2] & IEC958_AES2_PRO_WORDLEN_24_20) {
-			/* Does this work for LE systems ??? */
-			data = iec958_getbits(20);
-			data <<= 8;
-		} else {
-			data = iec958_getbits(16);
-			data <<= 12;
-		}
-	}
-
-	/*
-	 * Set one of the 192 bits of the channel status (AES3 and higher)
-	 */
-	if (status[byte] & mask)
-		data |= 0x40000000;
-
-	if (iec958_parity(data))	/* parity bit 4-30 */
-		data |= 0x80000000;
-
-	/* Preamble */
-	if      (!cm->spdif_counter)
-		data |= 0x03;		/* Block start, 'Z' */
-	else if (cm->spdif_counter % 2)
-		data |= 0x05;		/* odd sub frame, 'Y' */
-	else
-		data |= 0x09;		/* even sub frame, 'X' */
-
-	/*
-	 * sub frame counter: 2 sub frame are one audio frame
-	 * and 192 frames are one block
-	 */
-	cm->spdif_counter = (++cm->spdif_counter) % 384;
-
-	return data;
-}
-# endif /* if USE_AES_IEC958 */
-
-static int snd_cmipci_ac3_copy(snd_pcm_substream_t *subs, int channel,
-			       snd_pcm_uframes_t pos, void *src,
-			       snd_pcm_uframes_t count)
-{
-	cmipci_t *cm = snd_pcm_substream_chip(subs);
-	u32 *dst;
-	snd_pcm_uframes_t offset;
-	snd_pcm_runtime_t *runtime = subs->runtime;
-#ifndef USE_AES_IEC958
-	u16 *srcp = src, val;
-#else
-	char buf[480];         /* bits can be divided by 20, 24, 16 */
-	size_t bytes = frames_to_bytes(runtime, count);
-#endif
-
-
-	if (!cm->channel[CM_CH_PLAY].ac3_shift) {
-		if (copy_from_user(runtime->dma_area +
-				   frames_to_bytes(runtime, pos), src,
-				   frames_to_bytes(runtime, count)))
-			return -EFAULT;
-		return 0;
-	}
-
-	if (! access_ok(VERIFY_READ, src, count))
-		return -EFAULT;
-
-	/* frame = 16bit stereo */
-	offset = (pos << 1) % (cm->channel[CM_CH_PLAY].dma_size << 2);
-	dst = (u32*)(runtime->dma_area + offset);
-# ifndef USE_AES_IEC958
-	count /= 2;
-	while (count-- > 0) {
-		get_user(val, srcp);
-		srcp++;
-		*dst++ = convert_ac3_32bit(cm, val);
-	}
-# else
-	while (bytes) {
-		size_t c = bytes;
-
-		if (c > sizeof(buf))
-			c = sizeof(buf);
-
-		if (copy_from_user(buf, src, c))
-			return -EFAULT;
-		bytes -= c;
-		src   += c;
-
-		iec958_init_bitstream(buf, c*8);
-		while (iec958_bits_avail()) {
-			*(dst++) = iec958_subframe(cm, cm->spdif_channel);
-			if (iec958_error())
-				return -EINVAL;
-		}
-		iec958_clear_bitstream();
-	}
-# endif
-	return 0;
-}
-
-static int snd_cmipci_ac3_silence(snd_pcm_substream_t *subs, int channel,
-				  snd_pcm_uframes_t pos,
-				  snd_pcm_uframes_t count)
-{
-	cmipci_t *cm = snd_pcm_substream_chip(subs);
-	u32 *dst;
-	snd_pcm_uframes_t offset;
-	snd_pcm_runtime_t *runtime = subs->runtime;
-# ifdef USE_AES_IEC958
-	char buf[480];		/* bits can be divided by 20, 24, 16 */
-	size_t bytes = frames_to_bytes(runtime, count);
-# endif
-	if (! cm->channel[CM_CH_PLAY].ac3_shift)
-		return snd_pcm_format_set_silence(runtime->format,
-						  runtime->dma_area + frames_to_bytes(runtime, pos), count);
-	
-	/* frame = 16bit stereo */
-	offset = (pos << 1) % (cm->channel[CM_CH_PLAY].dma_size << 2);
-	dst = (u32*)(subs->runtime->dma_area + offset);
-# ifndef USE_AES_IEC958
-	count /= 2;
-	while (count-- > 0) {
-		*dst++ = convert_ac3_32bit(cm, 0);
-	}
-# else
-	while (bytes) {
-		size_t c = bytes;
-
-		if (c > sizeof(buf))
-			c = sizeof(buf);
-
-		/* Q: Does this function know about 24bit silence? */
-		if (snd_pcm_format_set_silence(runtime->format, buf, bytes_to_frames(runtime, c)))
-			return -EINVAL;
-
-		iec958_init_bitstream(buf, c*8);
-		while (iec958_bits_avail()) {
-			*(dst++) = iec958_subframe(cm, cm->spdif_channel);
-			if (iec958_error())
-				return -EINVAL;
-		}
-		iec958_clear_bitstream();
-	}
-# endif
-	return 0;
-}
-#endif /* DO_SOFT_AC3 */
-
 
 /*
  * hw preparation for spdif
@@ -1404,9 +1036,6 @@
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	for (i = 0; i < 4; i++)
 		ucontrol->value.iec958.status[i] = (chip->dig_pcm_status >> (i * 8)) & 0xff;
-#ifdef USE_AES_IEC958
-	ucontrol = chip->spdif_channel;
-#endif
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	return 0;
 }
@@ -1425,9 +1054,6 @@
 		val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
 	change = val != chip->dig_pcm_status;
 	chip->dig_pcm_status = val;
-#ifdef USE_AES_IEC958
-	chip->spdif_channel = ucontrol;
-#endif
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	return change;
 }
@@ -1504,9 +1130,6 @@
 /* spinlock held! */
 static void setup_ac3(cmipci_t *cm, snd_pcm_substream_t *subs, int do_ac3, int rate)
 {
-	cm->channel[CM_CH_PLAY].ac3_shift = 0;
-	cm->spdif_counter = 0;
-
 	if (do_ac3) {
 		/* AC3EN for 037 */
 		snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_AC3EN1);
@@ -1519,9 +1142,6 @@
 			snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);
 			snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
 		} else { /* can_ac3_sw */
-#ifdef DO_SOFT_AC3
-			/* FIXME: ugly hack! */
-			subs->runtime->buffer_size /= 2;
 			/* SPD32SEL for 037 & 039, 0x20 */
 			snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
 			/* set 176K sample rate to fix 033 HW bug */
@@ -1532,8 +1152,6 @@
 					snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_PLAYBACK_SRATE_176K);
 				}
 			}
-			cm->channel[CM_CH_PLAY].ac3_shift = 1; /* use 32bit */
-#endif /* DO_SOFT_AC3 */
 		}
 
 	} else {
@@ -1550,11 +1168,9 @@
 				snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);
 			}
 		} else {
-#ifdef DO_SOFT_AC3
 			snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
 			snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL);
 			snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_PLAYBACK_SRATE_176K);
-#endif /* DO_SOFT_AC3 */
 		}
 	}
 }
@@ -1604,15 +1220,12 @@
 {
 	cmipci_t *cm = snd_pcm_substream_chip(substream);
 	int rate = substream->runtime->rate;
-	int do_spdif, do_ac3;
+	int do_spdif, do_ac3 = 0;
 	do_spdif = ((rate == 44100 || rate == 48000) &&
 		    substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE &&
 		    substream->runtime->channels == 2);
-	do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO;
-#ifdef DO_SOFT_AC3
-	if (do_ac3 && cm->can_ac3_sw)
-		do_spdif = 0;
-#endif
+	if (do_spdif && cm->can_ac3_hw) 
+		do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO;
 	setup_spdif_playback(cm, substream, do_spdif, do_ac3);
 	return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream);
 }
@@ -1621,7 +1234,12 @@
 static int snd_cmipci_playback_spdif_prepare(snd_pcm_substream_t *substream)
 {
 	cmipci_t *cm = snd_pcm_substream_chip(substream);
-	setup_spdif_playback(cm, substream, 1, cm->dig_pcm_status & IEC958_AES0_NONAUDIO);
+	int do_ac3;
+	if (cm->can_ac3_hw) 
+		do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO;
+	else
+		do_ac3 = 1; /* doesn't matter */
+	setup_spdif_playback(cm, substream, 1, do_ac3);
 	return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream);
 }
 
@@ -1768,8 +1386,9 @@
 /* spdif playback on channel A */
 static snd_pcm_hardware_t snd_cmipci_playback_spdif =
 {
-	.info =			(SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE),
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |
+				 SNDRV_PCM_INFO_MMAP_VALID),
 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 	.rate_min =		44100,
@@ -1784,6 +1403,26 @@
 	.fifo_size =		0,
 };
 
+/* spdif playback on channel A (32bit, IEC958 subframes) */
+static snd_pcm_hardware_t snd_cmipci_playback_iec958_subframe =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+	.rate_min =		44100,
+	.rate_max =		48000,
+	.channels_min =		2,
+	.channels_max =		2,
+	.buffer_bytes_max =	(128*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(128*1024),
+	.periods_min =		2,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
 /* spdif capture on channel B */
 static snd_pcm_hardware_t snd_cmipci_capture_spdif =
 {
@@ -1921,13 +1560,13 @@
 
 	if ((err = open_device_check(cm, CM_OPEN_SPDIF_PLAYBACK, substream)) < 0) /* use channel A */
 		return err;
-	runtime->hw = snd_cmipci_playback_spdif;
-#ifdef DO_SOFT_AC3
-	if (cm->can_ac3_hw)
-#endif
-		runtime->hw.info |= SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID;
-	if (cm->chip_version >= 37)
-		runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE;
+	if (cm->can_ac3_hw) {
+		runtime->hw = snd_cmipci_playback_spdif;
+		if (cm->chip_version >= 37)
+			runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE;
+	} else {
+		runtime->hw = snd_cmipci_playback_iec958_subframe;
+	}
 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000);
 	cm->dig_pcm_status = cm->dig_status;
 	return 0;
@@ -2034,21 +1673,6 @@
 	.pointer =	snd_cmipci_playback_pointer,
 };
 
-#ifdef DO_SOFT_AC3
-static snd_pcm_ops_t snd_cmipci_playback_spdif_soft_ops = {
-	.open =		snd_cmipci_playback_spdif_open,
-	.close =	snd_cmipci_playback_spdif_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_cmipci_hw_params,
-	.hw_free =	snd_cmipci_playback_hw_free,
-	.prepare =	snd_cmipci_playback_spdif_prepare,	/* set up rate */
-	.trigger =	snd_cmipci_playback_trigger,
-	.pointer =	snd_cmipci_playback_pointer,
-	.copy =		snd_cmipci_ac3_copy,
-	.silence =	snd_cmipci_ac3_silence,
-};
-#endif
-
 static snd_pcm_ops_t snd_cmipci_capture_spdif_ops = {
 	.open =		snd_cmipci_capture_spdif_open,
 	.close =	snd_cmipci_capture_spdif_close,
@@ -2125,14 +1749,7 @@
 	if (err < 0)
 		return err;
 
-#ifdef DO_SOFT_AC3
-	if (cm->can_ac3_hw)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_spdif_ops);
-	else
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_spdif_soft_ops);
-#else
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_spdif_ops);
-#endif
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cmipci_capture_spdif_ops);
 
 	pcm->private_data = cm;
@@ -2770,16 +2387,17 @@
 			if (err < 0)
 				return err;
 		}
-		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_default, cm))) < 0)
-			return err;
-		kctl->id.device = pcm_spdif_device;
-		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_mask, cm))) < 0)
-			return err;
-		kctl->id.device = pcm_spdif_device;
-		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_stream, cm))) < 0)
-			return err;
-		kctl->id.device = pcm_spdif_device;
-		cm->spdif_pcm_ctl = kctl;
+		if (cm->can_ac3_hw) {
+			if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_default, cm))) < 0)
+				return err;
+			kctl->id.device = pcm_spdif_device;
+			if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_mask, cm))) < 0)
+				return err;
+			kctl->id.device = pcm_spdif_device;
+			if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_stream, cm))) < 0)
+				return err;
+			kctl->id.device = pcm_spdif_device;
+		}
 		if (cm->chip_version <= 37) {
 			sw = snd_cmipci_old_mixer_switches;
 			for (idx = 0; idx < num_controls(snd_cmipci_old_mixer_switches); idx++, sw++) {
@@ -2917,6 +2535,8 @@
 	if (cm->can_multi_ch)
 		sprintf(cm->card->driver + strlen(cm->card->driver),
 			"-MC%d", cm->max_channels);
+	else if (cm->can_ac3_sw)
+		strcpy(cm->card->driver + strlen(cm->card->driver), "-SWIEC");
 }
 
 
@@ -3013,9 +2633,7 @@
 
 	cm->chip_version = 0;
 	cm->max_channels = 2;
-#ifdef DO_SOFT_AC3
 	cm->do_soft_ac3 = soft_ac3[dev];
-#endif
 
 	query_chip(cm);
 
@@ -3264,15 +2882,7 @@
 	
 static int __init alsa_card_cmipci_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "C-Media PCI soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_cmipci_exit(void)
@@ -3282,34 +2892,3 @@
 
 module_init(alsa_card_cmipci_init)
 module_exit(alsa_card_cmipci_exit)
-
-#ifndef MODULE
-
-/* format is: snd-cmipci=enable,index,id,
-			 mpu_port,fm_port,soft_ac3,joystick_port */
-
-static int __init alsa_card_cmipci_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 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2
-#ifdef DO_SOFT_AC3
-	       && get_option(&str,&soft_ac3[nr_dev]) == 2
-#endif
-#ifdef SUPPORT_JOYSTICK
-	       && get_option(&str,&joystick_port[nr_dev]) == 2
-#endif
-	       );
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-cmipci=", alsa_card_cmipci_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/cs4281.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/cs4281.c	2004-05-27 18:34:20.000000000 +0100
@@ -27,13 +27,13 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
 #include <sound/ac97_codec.h>
 #include <sound/opl3.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 
@@ -47,17 +47,18 @@
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable switches */
 static int dual_codec[SNDRV_CARDS];	/* dual codec */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for CS4281 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for CS4281 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable CS4281 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(dual_codec, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dual_codec, bool, boot_devs, 0444);
 MODULE_PARM_DESC(dual_codec, "Secondary Codec ID (0 = disabled).");
 MODULE_PARM_SYNTAX(dual_codec, SNDRV_ENABLED ",allows:{{0,3}}");
 
@@ -1395,7 +1396,8 @@
 
 static int snd_cs4281_chip_init(cs4281_t *chip); /* defined below */
 #ifdef CONFIG_PM
-static int snd_cs4281_set_power_state(snd_card_t *card, unsigned int power_state);
+static int cs4281_suspend(snd_card_t *card, unsigned int state);
+static int cs4281_resume(snd_card_t *card, unsigned int state);
 #endif
 
 static int __devinit snd_cs4281_create(snd_card_t * card,
@@ -1461,10 +1463,7 @@
 
 	snd_cs4281_proc_init(chip);
 
-#ifdef CONFIG_PM
-	card->set_power_state = snd_cs4281_set_power_state;
-	card->power_state_private_data = chip;
-#endif
+	snd_card_set_pm_callback(card, cs4281_suspend, cs4281_resume, chip);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_cs4281_free(chip);
@@ -1481,7 +1480,9 @@
 {
 	unsigned int tmp;
 	int timeout;
+	int retry_count = 2;
 
+      __retry:
 	tmp = snd_cs4281_peekBA0(chip, BA0_CFLR);
 	if (tmp != BA0_CFLR_DEFAULT) {
 		snd_cs4281_pokeBA0(chip, BA0_CFLR, BA0_CFLR_DEFAULT);
@@ -1629,6 +1630,8 @@
 		snd_cs4281_delay_long();
 	} while (timeout-- > 0);
 
+	if (--retry_count > 0)
+		goto __retry;
 	snd_printk(KERN_ERR "never read ISV3 and ISV4 from AC'97\n");
 	return -EIO;
 
@@ -1999,15 +2002,14 @@
 		return err;
 	}
 
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_cs4281_remove(struct pci_dev *pci)
 {
-	cs4281_t *chip = pci_get_drvdata(pci);
-	snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -2036,17 +2038,19 @@
 
 #define CLKCR1_CKRA                             0x00010000L
 
-static void cs4281_suspend(cs4281_t *chip)
+static int cs4281_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	cs4281_t *chip = snd_magic_cast(cs4281_t, card->pm_private_data, return -EINVAL);
 	u32 ulCLK;
 	unsigned int i;
 
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
-
 	snd_pcm_suspend_all(chip->pcm);
 
+	if (chip->ac97)
+		snd_ac97_suspend(chip->ac97);
+	if (chip->ac97_secondary)
+		snd_ac97_suspend(chip->ac97_secondary);
+
 	ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
 	ulCLK |= CLKCR1_CKRA;
 	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
@@ -2076,17 +2080,15 @@
 	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void cs4281_resume(cs4281_t *chip)
+static int cs4281_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	cs4281_t *chip = snd_magic_cast(cs4281_t, card->pm_private_data, return -EINVAL);
 	unsigned int i;
 	u32 ulCLK;
 
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
-
 	pci_enable_device(chip->pci);
 
 	ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
@@ -2110,41 +2112,8 @@
 	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_cs4281_suspend(struct pci_dev *dev, u32 state)
-{
-	cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return -ENXIO);
-	cs4281_suspend(chip);
-	return 0;
-}
-static int snd_cs4281_resume(struct pci_dev *dev)
-{
-	cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return -ENXIO);
-	cs4281_resume(chip);
 	return 0;
 }
-
-/* callback */
-static int snd_cs4281_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	cs4281_t *chip = snd_magic_cast(cs4281_t, card->power_state_private_data, return -ENXIO);
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		cs4281_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		cs4281_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
 #endif /* CONFIG_PM */
 
 static struct pci_driver driver = {
@@ -2152,23 +2121,12 @@
 	.id_table = snd_cs4281_ids,
 	.probe = snd_cs4281_probe,
 	.remove = __devexit_p(snd_cs4281_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_cs4281_suspend,
-	.resume = snd_cs4281_resume,
-#endif
+	SND_PCI_PM_CALLBACKS
 };
 	
 static int __init alsa_card_cs4281_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "CS4281 soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_cs4281_exit(void)
@@ -2178,24 +2136,3 @@
 
 module_init(alsa_card_cs4281_init)
 module_exit(alsa_card_cs4281_exit)
-
-#ifndef MODULE
-
-/* format is: snd-cs4281=enable,index,id */
-
-static int __init alsa_card_cs4281_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-cs4281=", alsa_card_cs4281_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/cs46xx/cs46xx.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/cs46xx/cs46xx.c	2004-05-27 18:34:20.000000000 +0100
@@ -29,9 +29,9 @@
 #include <linux/pci.h>
 #include <linux/time.h>
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/cs46xx.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -52,23 +52,24 @@
 static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
 static int thinkpad[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
 static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for the CS46xx soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for the CS46xx soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable CS46xx soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(external_amp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(external_amp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(external_amp, "Force to enable external amplifer.");
 MODULE_PARM_SYNTAX(external_amp, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
-MODULE_PARM(thinkpad, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(thinkpad, bool, boot_devs, 0444);
 MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control.");
 MODULE_PARM_SYNTAX(thinkpad, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
-MODULE_PARM(mmap_valid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mmap_valid, bool, boot_devs, 0444);
 MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
 MODULE_PARM_SYNTAX(mmap_valid, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
 
@@ -157,31 +158,14 @@
 		return err;
 	}
 
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int snd_card_cs46xx_suspend(struct pci_dev *pci, u32 state)
-{
-	cs46xx_t *chip = snd_magic_cast(cs46xx_t, pci_get_drvdata(pci), return -ENXIO);
-	snd_cs46xx_suspend(chip);
-	return 0;
-}
-static int snd_card_cs46xx_resume(struct pci_dev *pci)
-{
-	cs46xx_t *chip = snd_magic_cast(cs46xx_t, pci_get_drvdata(pci), return -ENXIO);
-	snd_cs46xx_resume(chip);
-	return 0;
-}
-#endif
-
 static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci)
 {
-	cs46xx_t *chip = snd_magic_cast(cs46xx_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -190,23 +174,12 @@
 	.id_table = snd_cs46xx_ids,
 	.probe = snd_card_cs46xx_probe,
 	.remove = __devexit_p(snd_card_cs46xx_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_card_cs46xx_suspend,
-	.resume = snd_card_cs46xx_resume,
-#endif
+	SND_PCI_PM_CALLBACKS
 };
 
 static int __init alsa_card_cs46xx_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Sound Fusion CS46xx soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_cs46xx_exit(void)
@@ -216,27 +189,3 @@
 
 module_init(alsa_card_cs46xx_init)
 module_exit(alsa_card_cs46xx_exit)
-
-#ifndef MODULE
-
-/* format is: snd-cs46xx=enable,index,id,mmap_valid,external_amp,thinkpad */
-
-static int __init alsa_card_cs46xx_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 &&
-	       get_option(&str,&mmap_valid[nr_dev]) == 2 &&
-	       get_option(&str,&external_amp[nr_dev]) == 2 &&
-	       get_option(&str,&thinkpad[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-cs46xx=", alsa_card_cs46xx_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/cs46xx/cs46xx_lib.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/cs46xx/cs46xx_lib.c	2004-05-27 18:34:20.000000000 +0100
@@ -3784,17 +3784,19 @@
  * APM support
  */
 #ifdef CONFIG_PM
-void snd_cs46xx_suspend(cs46xx_t *chip)
+static int snd_cs46xx_suspend(snd_card_t *card, unsigned int state)
 {
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, card->pm_private_data, return -EINVAL);
 	int amp_saved;
 
-	snd_card_t *card = chip->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
 	snd_pcm_suspend_all(chip->pcm);
 	// chip->ac97_powerdown = snd_cs46xx_codec_read(chip, AC97_POWER_CONTROL);
 	// chip->ac97_general_purpose = snd_cs46xx_codec_read(chip, BA0_AC97_GENERAL_PURPOSE);
+
+	snd_ac97_suspend(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
+	if (chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])
+		snd_ac97_suspend(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
+
 	amp_saved = chip->amplifier;
 	/* turn off amp */
 	chip->amplifier_ctrl(chip, -chip->amplifier);
@@ -3803,16 +3805,14 @@
 	chip->active_ctrl(chip, -chip->amplifier);
 	chip->amplifier = amp_saved; /* restore the status */
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-void snd_cs46xx_resume(cs46xx_t *chip)
+static int snd_cs46xx_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, card->pm_private_data, return -EINVAL);
 	int amp_saved;
 
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
-
 	pci_enable_device(chip->pci);
 	amp_saved = chip->amplifier;
 	chip->amplifier = 0;
@@ -3832,6 +3832,8 @@
 #endif
 
 	snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
+	if (chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])
+		snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
 
 	if (amp_saved)
 		chip->amplifier_ctrl(chip, 1); /* turn amp on */
@@ -3839,25 +3841,6 @@
 		chip->active_ctrl(chip, -1); /* disable CLKRUN */
 	chip->amplifier = amp_saved;
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_cs46xx_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	cs46xx_t *chip = snd_magic_cast(cs46xx_t, card->power_state_private_data, return -ENXIO);
-
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		snd_cs46xx_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		snd_cs46xx_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
 #endif /* CONFIG_PM */
@@ -4010,10 +3993,7 @@
 
 	snd_cs46xx_proc_init(card, chip);
 
-#ifdef CONFIG_PM
-	card->set_power_state = snd_cs46xx_set_power_state;
-	card->power_state_private_data = chip;
-#endif
+	snd_card_set_pm_callback(card, snd_cs46xx_suspend, snd_cs46xx_resume, chip);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_cs46xx_free(chip);
--- diff/sound/pci/emu10k1/emu10k1.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/emu10k1/emu10k1.c	2004-05-27 18:34:20.000000000 +0100
@@ -23,9 +23,9 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -49,32 +49,33 @@
 static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
 static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
 static int enable_ir[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for the EMU10K1 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable the EMU10K1 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(extin, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(extin, int, boot_devs, 0444);
 MODULE_PARM_DESC(extin, "Available external inputs for FX8010. Zero=default.");
 MODULE_PARM_SYNTAX(extin, SNDRV_ENABLED "allows:{{0,0x0ffff}},base:16");
-MODULE_PARM(extout, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(extout, int, boot_devs, 0444);
 MODULE_PARM_DESC(extout, "Available external outputs for FX8010. Zero=default.");
 MODULE_PARM_SYNTAX(extout, SNDRV_ENABLED "allows:{{0,0x0ffff}},base:16");
-MODULE_PARM(seq_ports, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(seq_ports, int, boot_devs, 0444);
 MODULE_PARM_DESC(seq_ports, "Allocated sequencer ports for internal synthesizer.");
 MODULE_PARM_SYNTAX(seq_ports, SNDRV_ENABLED "allows:{{0,32}}");
-MODULE_PARM(max_synth_voices, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(max_synth_voices, int, boot_devs, 0444);
 MODULE_PARM_DESC(max_synth_voices, "Maximum number of voices for WaveTable.");
 MODULE_PARM_SYNTAX(max_synth_voices, SNDRV_ENABLED);
-MODULE_PARM(max_buffer_size, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(max_buffer_size, int, boot_devs, 0444);
 MODULE_PARM_DESC(max_buffer_size, "Maximum sample buffer size in MB.");
 MODULE_PARM_SYNTAX(max_buffer_size, SNDRV_ENABLED);
-MODULE_PARM(enable_ir, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable_ir, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable_ir, "Enable IR.");
 MODULE_PARM_SYNTAX(enable_ir, SNDRV_ENABLE_DESC);
 
@@ -211,15 +212,7 @@
 
 static int __init alsa_card_emu10k1_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "EMU10K1/Audigy soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_emu10k1_exit(void)
@@ -229,27 +222,3 @@
 
 module_init(alsa_card_emu10k1_init)
 module_exit(alsa_card_emu10k1_exit)
-
-#ifndef MODULE
-
-/* format is: snd-emu10k1=enable,index,id,
-			  seq_ports,max_synth_voices */
-
-static int __init alsa_card_emu10k1_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 &&
-	       get_option(&str,&seq_ports[nr_dev]) == 2 &&
-	       get_option(&str,&max_synth_voices[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-emu10k1=", alsa_card_emu10k1_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/emu10k1/emu10k1_main.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/emu10k1/emu10k1_main.c	2004-05-27 18:34:20.000000000 +0100
@@ -690,7 +690,7 @@
 	if (extin_mask == 0)
 		extin_mask = 0x3fcf;
 	if (extout_mask == 0)
-		extout_mask = 0x1fff;
+		extout_mask = 0x7fff;
 	emu->fx8010.extin_mask = extin_mask;
 	emu->fx8010.extout_mask = extout_mask;
 
--- diff/sound/pci/emu10k1/emufx.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/emu10k1/emufx.c	2004-05-27 18:34:20.000000000 +0100
@@ -120,8 +120,8 @@
 	/* 0x0a */ "PCM Capture Left",
 	/* 0x0b */ "PCM Capture Right",
 	/* 0x0c */ "MIC Capture",
-	/* 0x0d */ NULL,
-	/* 0x0e */ NULL,
+	/* 0x0d */ "AC97 Surround Left",
+	/* 0x0e */ "AC97 Surround Right",
 	/* 0x0f */ NULL,
 	/* 0x10 */ NULL,
 	/* 0x11 */ "Analog Center",
@@ -2113,22 +2113,26 @@
 		for (z = 0; z < 2; z++)
 			OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
 
-	if (emu->fx8010.extout_mask & (1<<EXTOUT_CENTER)) {
+	if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
+		for (z = 0; z < 2; z++)
+			OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
+
+	if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
 #ifndef EMU10K1_CENTER_LFE_FROM_FRONT
-		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
+		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
 		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
 #else
-		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
+		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
 		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
 #endif
 	}
 
-	if (emu->fx8010.extout_mask & (1<<EXTOUT_LFE)) {
+	if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
 #ifndef EMU10K1_CENTER_LFE_FROM_FRONT
-		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
+		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
 		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
 #else
-		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
+		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
 		OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
 #endif
 	}
--- diff/sound/pci/emu10k1/emumixer.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/emu10k1/emumixer.c	2004-05-27 18:34:20.000000000 +0100
@@ -34,6 +34,8 @@
 
 #define chip_t emu10k1_t
 
+#define AC97_ID_STAC9758	0x83847658
+
 static int snd_emu10k1_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
@@ -531,6 +533,15 @@
 			snd_ac97_write(emu->ac97, AC97_REC_SEL, 0x0000);
 			c = audigy_remove_ctls;
 		} else {
+			/*
+			 * Credits for cards based on STAC9758:
+			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
+			 *   Voluspa <voluspa@comhem.se>
+			 */
+			if (emu->ac97->id == AC97_ID_STAC9758) {
+				emu->rear_ac97 = 1;
+				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
+			}
 			/* remove unused AC97 controls */
 			snd_ac97_write(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
 			snd_ac97_write(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
--- diff/sound/pci/ens1370.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ens1370.c	2004-05-27 18:34:20.000000000 +0100
@@ -27,6 +27,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -36,7 +37,6 @@
 #else
 #include <sound/ak4531_codec.h>
 #endif
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/asoundef.h>
 
@@ -86,23 +86,24 @@
 static int joystick[SNDRV_CARDS];
 #endif
 #endif
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Ensoniq AudioPCI soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Ensoniq AudioPCI soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Ensoniq AudioPCI soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 #ifdef SUPPORT_JOYSTICK
 #ifdef CHIP1371
-MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick_port, int, boot_devs, 0444);
 MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{1},{0x200},{0x208},{0x210},{0x218}},dialog:list");
 #else
-MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick, bool, boot_devs, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick.");
 MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 #endif
@@ -2371,15 +2372,7 @@
 	
 static int __init alsa_card_ens137x_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Ensoniq AudioPCI soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_ens137x_exit(void)
@@ -2389,36 +2382,3 @@
 
 module_init(alsa_card_ens137x_init)
 module_exit(alsa_card_ens137x_exit)
-
-#ifndef MODULE
-
-/* format is: snd-ens1370=enable,index,id,joystick */
-
-static int __init alsa_card_ens137x_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
-#ifdef SUPPORT_JOYSTICK
-#ifdef CHIP1371
-	       && get_option(&str,&joystick_port[nr_dev]) == 2
-#else
-	       && get_option(&str,&joystick[nr_dev]) == 2
-#endif
-#endif
-	       );
-	nr_dev++;
-	return 1;
-}
-
-#if defined(CHIP1370)
-__setup("snd-ens1370=", alsa_card_ens137x_setup);
-#elif defined(CHIP1371)
-__setup("snd-ens1371=", alsa_card_ens137x_setup);
-#endif
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/es1938.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/es1938.c	2004-05-27 18:34:20.000000000 +0100
@@ -53,12 +53,12 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/opl3.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/io.h>
@@ -84,14 +84,15 @@
 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 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for ESS Solo-1 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for ESS Solo-1 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable ESS Solo-1 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 
@@ -1700,15 +1701,7 @@
 
 static int __init alsa_card_es1938_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "ESS Solo-1 soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_es1938_exit(void)
@@ -1718,24 +1711,3 @@
 
 module_init(alsa_card_es1938_init)
 module_exit(alsa_card_es1938_exit)
-
-#ifndef MODULE
-
-/* format is: snd-es1938=enable,index,id */
-
-static int __init alsa_card_es1938_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-es1938=", alsa_card_es1938_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/es1968.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/es1968.c	2004-05-27 18:34:20.000000000 +0100
@@ -102,11 +102,11 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/mpu401.h>
 #include <sound/ac97_codec.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #define chip_t es1968_t
@@ -138,36 +138,37 @@
 #ifdef SUPPORT_JOYSTICK
 static int joystick[SNDRV_CARDS];
 #endif
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(total_bufsize, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(total_bufsize, int, boot_devs, 0444);
 MODULE_PARM_DESC(total_bufsize, "Total buffer size in kB.");
 MODULE_PARM_SYNTAX(total_bufsize, SNDRV_ENABLED ",allows:{{1,4096}},skill:advanced");
-MODULE_PARM(pcm_substreams_p, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_substreams_p, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_substreams_p, "PCM Playback substreams for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(pcm_substreams_p, SNDRV_ENABLED ",allows:{{1,8}}");
-MODULE_PARM(pcm_substreams_c, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_substreams_c, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_substreams_c, "PCM Capture substreams for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(pcm_substreams_c, SNDRV_ENABLED ",allows:{{0,8}}");
-MODULE_PARM(clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(clock, int, boot_devs, 0444);
 MODULE_PARM_DESC(clock, "Clock on " CARD_NAME " soundcard.  (0 = auto-detect)");
 MODULE_PARM_SYNTAX(clock, SNDRV_ENABLED);
-MODULE_PARM(use_pm, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(use_pm, int, boot_devs, 0444);
 MODULE_PARM_DESC(use_pm, "Toggle power-management.  (0 = off, 1 = on, 2 = auto)");
-MODULE_PARM_SYNTAX(use_pm, SNDRV_ENABLED ",allows:{{0,1,2}},skill:advanced");
-MODULE_PARM(enable_mpu, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_SYNTAX(use_pm, SNDRV_ENABLED ",allows:{{0,1,2}},default:2,skill:advanced");
+module_param_array(enable_mpu, int, boot_devs, 0444);
 MODULE_PARM_DESC(enable_mpu, "Enable MPU401.  (0 = off, 1 = on, 2 = auto)");
-MODULE_PARM_SYNTAX(enable_mpu, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
+MODULE_PARM_SYNTAX(enable_mpu, SNDRV_ENABLED ",allows:{{0,2}},default:2");
 #ifdef SUPPORT_JOYSTICK
-MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick, bool, boot_devs, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick.");
 MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 #endif
@@ -2415,30 +2416,27 @@
 /*
  * PM support
  */
-static void es1968_suspend(es1968_t *chip)
+static int es1968_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	es1968_t *chip = snd_magic_cast(es1968_t, card->pm_private_data, return -EINVAL);
 
 	if (! chip->do_pm)
-		return;
-
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
+		return 0;
 
 	snd_pcm_suspend_all(chip->pcm);
+	snd_ac97_suspend(chip->ac97);
 	snd_es1968_bob_stop(chip);
+	snd_es1968_set_acpi(chip, ACPI_D3);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void es1968_resume(es1968_t *chip)
+static int es1968_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	es1968_t *chip = snd_magic_cast(es1968_t, card->pm_private_data, return -EINVAL);
 
 	if (! chip->do_pm)
-		return;
-
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
+		return 0;
 
 	/* restore all our config */
 	pci_enable_device(chip->pci);
@@ -2460,47 +2458,17 @@
 		snd_es1968_bob_start(chip);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_es1968_suspend(struct pci_dev *dev, u32 state)
-{
-	es1968_t *chip = snd_magic_cast(es1968_t, pci_get_drvdata(dev), return -ENXIO);
-	es1968_suspend(chip);
 	return 0;
 }
-static int snd_es1968_resume(struct pci_dev *dev)
-{
-	es1968_t *chip = snd_magic_cast(es1968_t, pci_get_drvdata(dev), return -ENXIO);
-	es1968_resume(chip);
-	return 0;
-}
-
-/* callback */
-static int snd_es1968_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	es1968_t *chip = snd_magic_cast(es1968_t, card->power_state_private_data, return -ENXIO);
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		es1968_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		es1968_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
 #endif /* CONFIG_PM */
 
 static int snd_es1968_free(es1968_t *chip)
 {
-	if (chip->res_io_port)
-		snd_es1968_reset(chip);
+	if (chip->res_io_port) {
+		synchronize_irq(chip->irq);
+		outw(1, chip->io_port + 0x04); /* clear WP interrupts */
+		outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */
+	}
 
 #ifdef SUPPORT_JOYSTICK
 	if (chip->res_joystick) {
@@ -2534,6 +2502,7 @@
 };
 
 static struct ess_device_list pm_whitelist[] __devinitdata = {
+	{ TYPE_MAESTRO2E, 0x0e11 },	/* Compaq Armada */
 	{ TYPE_MAESTRO2E, 0x1028 },
 	{ TYPE_MAESTRO2E, 0x103c },
 	{ TYPE_MAESTRO2E, 0x1179 },
@@ -2636,12 +2605,8 @@
 
 	snd_es1968_chip_init(chip);
 
-#ifdef CONFIG_PM
-	if (chip->do_pm) {
-		card->set_power_state = snd_es1968_set_power_state;
-		card->power_state_private_data = chip;
-	}
-#endif
+	if (chip->do_pm)
+		snd_card_set_pm_callback(card, es1968_suspend, es1968_resume, chip);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_es1968_free(chip);
@@ -2763,16 +2728,14 @@
 		snd_card_free(card);
 		return err;
 	}
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_es1968_remove(struct pci_dev *pci)
 {
-	es1968_t *chip = snd_magic_cast(es1968_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -2781,71 +2744,18 @@
 	.id_table = snd_es1968_ids,
 	.probe = snd_es1968_probe,
 	.remove = __devexit_p(snd_es1968_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_es1968_suspend,
-	.resume = snd_es1968_resume,
-#endif
+	SND_PCI_PM_CALLBACKS
 };
 
 static int __init alsa_card_es1968_init(void)
 {
-	int err;
-
-        if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "ESS Maestro soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_es1968_exit(void)
 {
-#if 0 // do we really need this?
-	unregister_reboot_notifier(&snd_es1968_nb);
-#endif
 	pci_unregister_driver(&driver);
 }
 
 module_init(alsa_card_es1968_init)
 module_exit(alsa_card_es1968_exit)
-
-#ifndef MODULE
-
-/* format is: snd-es1968=enable,index,id,
-			 total_bufsize,
-			 pcm_substreams_p,
-			 pcm_substreams_c,
-			 clock,
-			 use_pm,
-			 enable_mpu,
-			 joystick
-*/
-
-static int __init alsa_card_es1968_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 &&
-	       get_option(&str,&total_bufsize[nr_dev]) == 2 &&
-	       get_option(&str,&pcm_substreams_p[nr_dev]) == 2 &&
-	       get_option(&str,&pcm_substreams_c[nr_dev]) == 2 &&
-	       get_option(&str,&clock[nr_dev]) == 2 &&
-	       get_option(&str,&use_pm[nr_dev]) == 2 &&
-	       get_option(&str,&enable_mpu[nr_dev]) == 2
-#ifdef SUPPORT_JOYSTICK
-	       && get_option(&str,&joystick[nr_dev]) == 2
-#endif
-	       );
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-es1968=", alsa_card_es1968_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/fm801.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/fm801.c	2004-05-27 18:34:20.000000000 +0100
@@ -25,12 +25,12 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/io.h>
@@ -60,17 +60,18 @@
  *  High 16-bits are video (radio) device number + 1
  */
 static int tea575x_tuner[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 };
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for the FM801 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(tea575x_tuner, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(tea575x_tuner, bool, boot_devs, 0444);
 MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner.");
 MODULE_PARM_SYNTAX(tea575x_tuner, SNDRV_ENABLE_DESC);
 
@@ -1482,15 +1483,7 @@
 
 static int __init alsa_card_fm801_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "ForteMedia FM801 soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_fm801_exit(void)
@@ -1500,25 +1493,3 @@
 
 module_init(alsa_card_fm801_init)
 module_exit(alsa_card_fm801_exit)
-
-#ifndef MODULE
-
-/* format is: snd-fm801=enable,index,id,tea575x_tuner */
-
-static int __init alsa_card_fm801_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 &&
-	       get_option(&str,&tea575x_tuner[nr_dev]));
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-fm801=", alsa_card_fm801_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/ice1712/Makefile	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/Makefile	2004-05-27 18:34:20.000000000 +0100
@@ -5,7 +5,7 @@
 
 snd-ice17xx-ak4xxx-objs := ak4xxx.o
 snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o prodigy.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
--- diff/sound/pci/ice1712/amp.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/amp.c	2004-05-27 18:34:20.000000000 +0100
@@ -54,10 +54,11 @@
 /* entry point */
 struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
 	{
-		VT1724_SUBDEVICE_AUDIO2000,
-		"AMP Ltd AUDIO2000",
-		snd_vt1724_amp_init,
-		snd_vt1724_amp_add_controls,
+		.subvendor = VT1724_SUBDEVICE_AUDIO2000,
+		.name = "AMP Ltd AUDIO2000",
+		.model = "amp2000",
+		.chip_init = snd_vt1724_amp_init,
+		.build_controls = snd_vt1724_amp_add_controls,
 	},
 	{ } /* terminator */
 };
--- diff/sound/pci/ice1712/aureon.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/aureon.c	2004-05-27 18:34:20.000000000 +0100
@@ -38,6 +38,25 @@
  *   the analog mixing but not easily controllable (it's not connected
  *   directly from envy24ht chip).  so let's leave it as it is.
  *
+ *
+ *   Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards
+ *      Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca>
+ *
+ *   version 0.82: Stable / not all features work yet (no communication with AC97 secondary)
+ *       added 64x/128x oversampling switch (should be 64x only for 96khz)
+ *       fixed some recording labels (still need to check the rest)
+ *       recording is working probably thanks to correct wm8770 initialization
+ *
+ *   version 0.5: Initial release:
+ *           working: analog output, mixer, headphone amplifier switch
+ *       not working: prety much everything else, at least i could verify that
+ *                    we have no digital output, no capture, pretty bad clicks and poops
+ *                    on mixer switch and other coll stuff.
+ *
+ * - Prodigy boards are equipped with AC97 STAC9744 chip , too.  it's used to do
+ *   the analog mixing but not easily controllable (it's not connected
+ *   directly from envy24ht chip).  so let's leave it as it is.
+ *
  */      
 
 #include <sound/driver.h>
@@ -77,12 +96,18 @@
 static void aureon_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits)
 {
 	unsigned int tmp;
+	unsigned int cscs;
 	int i;
 
 	tmp = snd_ice1712_gpio_read(ice);
 
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
+		cscs = PRODIGY_CS8415_CS;
+	else
+		cscs = AUREON_CS8415_CS;
+
 	snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_WM_DATA|AUREON_WM_CLK|
-					 AUREON_WM_CS|AUREON_CS8415_CS));
+					 AUREON_WM_CS|cscs));
 	tmp |= AUREON_WM_RW;
 	tmp &= ~cs;
 	snd_ice1712_gpio_write(ice, tmp);
@@ -135,6 +160,47 @@
 }
 
 /*
+ * DAC mute control
+ */
+static int wm_dac_mute_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 wm_dac_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	down(&ice->gpio_mutex);
+	val = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_MUTE);
+	ucontrol->value.integer.value[0] = ~val>>4 & 0x1;
+	up(&ice->gpio_mutex);
+	return 0;
+}
+
+static int wm_dac_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned short new, old;
+	int change;
+
+	snd_ice1712_save_gpio_status(ice);
+	old = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_MUTE);
+	new = (~ucontrol->value.integer.value[0]<<4&0x10) | (old&~0x10);
+	change = (new != old);
+	if (change)
+		wm_put(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_MUTE, new);
+	snd_ice1712_restore_gpio_status(ice);
+
+	return change;
+}
+
+/*
  * DAC volume attenuation mixer control
  */
 static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -192,6 +258,47 @@
 }
 
 /*
+ * ADC mute control
+ */
+static int wm_adc_mute_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 wm_adc_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	down(&ice->gpio_mutex);
+	val = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN);
+	ucontrol->value.integer.value[0] = ~val>>5 & 0x1;
+	up(&ice->gpio_mutex);
+	return 0;
+}
+
+static int wm_adc_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned short new, old;
+	int change;
+
+	snd_ice1712_save_gpio_status(ice);
+	old = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN);
+	new = (~ucontrol->value.integer.value[0]<<5&0x20) | (old&~0x20);
+	change = (new != old);
+	if (change)
+		wm_put(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN, new);
+	snd_ice1712_restore_gpio_status(ice);
+
+	return change;
+}
+
+/*
  * ADC gain mixer control
  */
 static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -227,10 +334,10 @@
 	snd_ice1712_save_gpio_status(ice);
 	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
 	nvol = ucontrol->value.integer.value[0];
-	ovol = wm_get(ice, idx) & 0x1f;
-	change = (ovol != nvol);
+	ovol = wm_get(ice, idx);
+	change = ((ovol & 0x1f)  != nvol);
 	if (change)
-		wm_put(ice, idx, nvol);
+		wm_put(ice, idx, nvol | (ovol & ~0x1f));
 	snd_ice1712_restore_gpio_status(ice);
 	return change;
 }
@@ -241,18 +348,15 @@
 static int wm_adc_mux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	static char *texts[] = {
-		"CD Left",
-		"CD Right",
-		"Aux Left",
-		"Aux Right",
-		"Line Left",
-		"Line Right",
-		"Mic Left",
-		"Mic Right",
+		"CD",		//AIN1
+		"Aux",		//AIN2
+		"Line",		//AIN3
+		"Mic",		//AIN4
+		"AC97"		//AIN5
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 2;
-	uinfo->value.enumerated.items = 8;
+	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]);
@@ -291,6 +395,127 @@
 }
 
 /*
+ * Headphone Amplifier
+ */
+static int aureon_set_headphone_amp(ice1712_t *ice, int enable)
+{
+	unsigned int tmp, tmp2;
+
+	tmp2 = tmp = snd_ice1712_gpio_read(ice);
+	if (enable)
+		tmp |= AUREON_HP_SEL;
+	else
+		tmp &= ~ AUREON_HP_SEL;
+	if (tmp != tmp2) {
+		snd_ice1712_gpio_write(ice, tmp);
+		return 1;
+	}
+	return 0;
+}
+
+static int aureon_get_headphone_amp(ice1712_t *ice)
+{
+	unsigned int tmp = snd_ice1712_gpio_read(ice);
+
+	return ( tmp & AUREON_HP_SEL )!= 0;
+}
+
+static int aureon_bool_info(snd_kcontrol_t *k, 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 aureon_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
+	return 0;
+}
+
+
+static int aureon_hpamp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+	return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
+}
+
+/*
+ * Deemphasis
+ */
+static int aureon_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
+	return 0;
+}
+
+static int aureon_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int temp, temp2;
+	temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
+	if (ucontrol->value.integer.value[0])
+		temp |= 0xf;
+	else
+		temp &= ~0xf;
+	if (temp != temp2) {
+		wm_put(ice, WM_DAC_CTRL2, temp);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * ADC Oversampling
+ */
+static int aureon_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[2] = { "128x", "64x"	};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+
+	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 aureon_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
+	return 0;
+}
+
+static int aureon_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	int temp, temp2;
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+	temp2 = temp = wm_get(ice, WM_MASTER);
+
+	if (ucontrol->value.enumerated.item[0])
+		temp |= 0x8;
+	else
+		temp &= ~0x8;
+
+	if (temp != temp2) {
+		wm_put(ice, WM_MASTER, temp);
+		return 1;
+	}
+	return 0;
+}
+
+/*
  * mixers
  */
 
@@ -315,6 +540,13 @@
 static snd_kcontrol_new_t wm_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = wm_dac_mute_info,
+		.get = wm_dac_mute_get,
+		.put = wm_dac_mute_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Volume",
 		.info = wm_dac_vol_info,
 		.get = wm_dac_vol_get,
@@ -323,6 +555,15 @@
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "ADC Switch",
+		.count = 2,
+		.info = wm_adc_mute_info,
+		.get = wm_adc_mute_get,
+		.put = wm_adc_mute_put,
+
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "ADC Volume",
 		.count = 2,
 		.info = wm_adc_vol_info,
@@ -336,6 +577,27 @@
 		.get = wm_adc_mux_get,
 		.put = wm_adc_mux_put,
 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Headphone Amplifier Switch",
+		.info = aureon_bool_info,
+		.get = aureon_hpamp_get,
+		.put = aureon_hpamp_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "DAC Deemphasis Switch",
+		.info = aureon_bool_info,
+		.get = aureon_deemp_get,
+		.put = aureon_deemp_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "ADC Oversampling",
+		.info = aureon_oversampling_info,
+		.get = aureon_oversampling_get,
+		.put = aureon_oversampling_put
+	},
 };
 
 
@@ -365,7 +627,7 @@
  */
 static int __devinit aureon_init(ice1712_t *ice)
 {
-	static unsigned short wm_inits[] = {
+	static unsigned short wm_inits_aureon[] = {
 		/* These come first to reduce init pop noise */
 		0x1b, 0x000,		/* ADC Mux */
 		0x1c, 0x009,		/* Out Mux1 */
@@ -399,20 +661,66 @@
 		0x15, 0x000,		/* no deemphasis, no ZFLG */
 		0x19, 0x000,		/* -12dB ADC/L */
 		0x1a, 0x000,		/* -12dB ADC/R */
+		(unsigned short)-1
+	};
+	static unsigned short wm_inits_prodigy[] = {
+
+		/* These come first to reduce init pop noise */
+		0x1b, 0x000,		/* ADC Mux */
+		0x1c, 0x009,		/* Out Mux1 */
+		0x1d, 0x009,		/* Out Mux2 */
+
+		0x18, 0x000,		/* All power-up */
+
+		0x16, 0x022,		/* I2S, normal polarity, 24bit, high-pass on */
+		0x17, 0x006,		/* 128fs, slave mode */
+
+		0x00, 0,		/* DAC1 analog mute */
+		0x01, 0,		/* DAC2 analog mute */
+		0x02, 0,		/* DAC3 analog mute */
+		0x03, 0,		/* DAC4 analog mute */
+		0x04, 0,		/* DAC5 analog mute */
+		0x05, 0,		/* DAC6 analog mute */
+		0x06, 0,		/* DAC7 analog mute */
+		0x07, 0,		/* DAC8 analog mute */
+		0x08, 0x100,		/* master analog mute */
+
+		0x09, 0x7f,		/* DAC1 digital full */
+		0x0a, 0x7f,		/* DAC2 digital full */
+		0x0b, 0x7f,		/* DAC3 digital full */
+		0x0c, 0x7f,		/* DAC4 digital full */
+		0x0d, 0x7f,		/* DAC5 digital full */
+		0x0e, 0x7f,		/* DAC6 digital full */
+		0x0f, 0x7f,		/* DAC7 digital full */
+		0x10, 0x7f,		/* DAC8 digital full */
+		0x11, 0x1FF,		/* master digital full */
+
+		0x12, 0x000,		/* phase normal */
+		0x13, 0x090,		/* unmute DAC L/R */
+		0x14, 0x000,		/* all unmute */
+		0x15, 0x000,		/* no deemphasis, no ZFLG */
+
+		0x19, 0x000,		/* -12dB ADC/L */
+		0x1a, 0x000,		/* -12dB ADC/R */
+		(unsigned short)-1
+
 	};
 	static unsigned short cs_inits[] = {
 		0x0441, /* RUN */
 		0x0100, /* no mute */
 		0x0200, /* */
 		0x0600, /* slave, 24bit */
+		(unsigned short)-1
 	};
 	unsigned int tmp;
-	unsigned int i;
+	unsigned short *p;
+	unsigned int cscs;
 
 	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
 		ice->num_total_dacs = 6;
 		ice->num_total_adcs = 6;
 	} else {
+		/* aureon 7.1 and prodigy 7.1 */
 		ice->num_total_dacs = 8;
 		ice->num_total_adcs = 8;
 	}
@@ -423,16 +731,22 @@
 		return -ENOMEM;
 	ice->akm_codecs = 1;
 
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
+		cscs = PRODIGY_CS8415_CS;
+	else
+		cscs = AUREON_CS8415_CS;
+
 	snd_ice1712_gpio_set_dir(ice, 0xbfffff); /* fix this for the time being */
 
 	/* reset the wm codec as the SPI mode */
 	snd_ice1712_save_gpio_status(ice);
-	snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS));
+	snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|
+					 cscs|AUREON_HP_SEL));
 	tmp = snd_ice1712_gpio_read(ice);
 	tmp &= ~AUREON_WM_RESET;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
-	tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
+	tmp |= AUREON_WM_CS | cscs;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
 	tmp |= AUREON_WM_RESET;
@@ -440,13 +754,19 @@
 	udelay(1);
 
 	/* initialize WM8770 codec */
-	for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
-		wm_put(ice, wm_inits[i], wm_inits[i+1]);
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
+		p = wm_inits_prodigy;
+	else
+		p = wm_inits_aureon;
+	for (; *p != (unsigned short)-1; p += 2)
+		wm_put(ice, p[0], p[1]);
 
 	/* initialize CS8415A codec */
-	for (i = 0; i < ARRAY_SIZE(cs_inits); i++)
-		aureon_spi_write(ice, AUREON_CS8415_CS,
-				 cs_inits[i] | 0x200000, 24);
+	for (p = cs_inits; *p != (unsigned short)-1; p++)
+		aureon_spi_write(ice, cscs,
+				 *p | 0x200000, 24);
+
+	aureon_set_headphone_amp(ice, 1);
 
 	snd_ice1712_restore_gpio_status(ice);
 
@@ -460,7 +780,7 @@
  */
 
 static unsigned char aureon51_eeprom[] __devinitdata = {
-	0x12,	/* SYSCONF: clock 512, mpu401, spdif-in/ADC, 3DACs */
+	0x2a,	/* SYSCONF: clock 512, mpu401, spdif-in/ADC, 3DACs */
 	0x80,	/* ACLINK: I2S */
 	0xf8,	/* I2S: vol, 96k, 24bit, 192k */
 	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
@@ -476,7 +796,23 @@
 };
 
 static unsigned char aureon71_eeprom[] __devinitdata = {
-	0x13,	/* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */
+	0x2b,	/* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */
+	0x80,	/* ACLINK: I2S */
+	0xf8,	/* I2S: vol, 96k, 24bit, 192k */
+	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
+	0xff,	/* GPIO_DIR */
+	0xff,	/* GPIO_DIR1 */
+	0xbf,	/* GPIO_DIR2 */
+	0x00,	/* GPIO_MASK */
+	0x00,	/* GPIO_MASK1 */
+	0x00,	/* GPIO_MASK2 */
+	0x00,	/* GPIO_STATE */
+	0x00,	/* GPIO_STATE1 */
+	0x00,	/* GPIO_STATE2 */
+};
+
+static unsigned char prodigy71_eeprom[] __devinitdata = {
+	0x2b,	/* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */
 	0x80,	/* ACLINK: I2S */
 	0xf8,	/* I2S: vol, 96k, 24bit, 192k */
 	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
@@ -496,6 +832,7 @@
 	{
 		.subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
 		.name = "Terratec Aureon 5.1-Sky",
+		.model = "aureon51",
 		.chip_init = aureon_init,
 		.build_controls = aureon_add_controls,
 		.eeprom_size = sizeof(aureon51_eeprom),
@@ -504,10 +841,29 @@
 	{
 		.subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
 		.name = "Terratec Aureon 7.1-Space",
+		.model = "aureon71",
 		.chip_init = aureon_init,
 		.build_controls = aureon_add_controls,
 		.eeprom_size = sizeof(aureon71_eeprom),
 		.eeprom_data = aureon71_eeprom,
 	},
+ 	{
+ 		.subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
+ 		.name = "Terratec Aureon 7.1-Universe",
+		/* model not needed - identical with 7.1-Space */
+ 		.chip_init = aureon_init,
+ 		.build_controls = aureon_add_controls,
+ 		.eeprom_size = sizeof(aureon71_eeprom),
+ 		.eeprom_data = aureon71_eeprom,
+	},
+	{
+		.subvendor = VT1724_SUBDEVICE_PRODIGY71,
+		.name = "Audiotrak Prodigy 7.1",
+		.model = "prodigy71",
+		.chip_init = aureon_init,
+		.build_controls = aureon_add_controls,
+		.eeprom_size = sizeof(prodigy71_eeprom),
+		.eeprom_data = prodigy71_eeprom,
+	},
 	{ } /* terminator */
 };
--- diff/sound/pci/ice1712/aureon.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/aureon.h	2004-05-27 18:34:20.000000000 +0100
@@ -25,10 +25,14 @@
  */      
 
 #define  AUREON_DEVICE_DESC 	       "{Terratec,Aureon 5.1 Sky},"\
-				       "{Terratec,Aureon 7.1 Space},"
+				       "{Terratec,Aureon 7.1 Space},"\
+				       "{Terratec,Aureon 7.1 Universe}," \
+					"{AudioTrak,Prodigy 7.1},"
 
 #define VT1724_SUBDEVICE_AUREON51_SKY	0x3b154711	/* Aureon 5.1 Sky */
 #define VT1724_SUBDEVICE_AUREON71_SPACE	0x3b154511	/* Aureon 7.1 Space */
+#define VT1724_SUBDEVICE_AUREON71_UNIVERSE	0x3b155311	/* Aureon 7.1 Universe */
+#define VT1724_SUBDEVICE_PRODIGY71	0x33495345	/* PRODIGY 7.1 */
 
 extern struct snd_ice1712_card_info  snd_vt1724_aureon_cards[];
 
@@ -44,4 +48,8 @@
 #define AUREON_HP_SEL		(1 << 14)
 #define AUREON_WM_CS		(1 << 12)
 
+/* Prodigy has different pin assignment for chip select */
+#define PRODIGY_CS8415_CS	(1 << 23)
+#define PRODIGY_CS8415_CDTO	(1 << 22)
+
 #endif /* __SOUND_AUREON_H */
--- diff/sound/pci/ice1712/delta.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/delta.c	2004-05-27 18:34:20.000000000 +0100
@@ -692,56 +692,64 @@
 /* entry point */
 struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
 	{
-		ICE1712_SUBDEVICE_DELTA1010,
-		"M Audio Delta 1010",
-		snd_ice1712_delta_init,
-		snd_ice1712_delta_add_controls,
-	},
-	{
-		ICE1712_SUBDEVICE_DELTADIO2496,
-		"M Audio Delta DiO 2496",
-		snd_ice1712_delta_init,
-		snd_ice1712_delta_add_controls,
-		1, /* NO MPU */
-	},
-	{
-		ICE1712_SUBDEVICE_DELTA66,
-		"M Audio Delta 66",
-		snd_ice1712_delta_init,
-		snd_ice1712_delta_add_controls,
-		1, /* NO MPU */
-	},
-	{
-		ICE1712_SUBDEVICE_DELTA44,
-		"M Audio Delta 44",
-		snd_ice1712_delta_init,
-		snd_ice1712_delta_add_controls,
-		1, /* NO MPU */
-	},
-	{
-		ICE1712_SUBDEVICE_AUDIOPHILE,
-		"M Audio Audiophile 24/96",
-		snd_ice1712_delta_init,
-		snd_ice1712_delta_add_controls,
-	},
-	{
-		ICE1712_SUBDEVICE_DELTA410,
-		"M Audio Delta 410",
-		snd_ice1712_delta_init,
-		snd_ice1712_delta_add_controls,
-	},
-	{
-		ICE1712_SUBDEVICE_DELTA1010LT,
-		"M Audio Delta 1010LT",
-		snd_ice1712_delta_init,
-		snd_ice1712_delta_add_controls,
-	},
-	{
-		ICE1712_SUBDEVICE_VX442,
-		"Digigram VX442",
-		snd_ice1712_delta_init,
-		snd_ice1712_delta_add_controls,
-		1, /* NO MPU */
+		.subvendor = ICE1712_SUBDEVICE_DELTA1010,
+		.name = "M Audio Delta 1010",
+		.model = "delta1010",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_DELTADIO2496,
+		.name = "M Audio Delta DiO 2496",
+		.model = "dio2496",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+		.no_mpu401 = 1,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_DELTA66,
+		.name = "M Audio Delta 66",
+		.model = "delta66",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+		.no_mpu401 = 1,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_DELTA44,
+		.name = "M Audio Delta 44",
+		.model = "delta44",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+		.no_mpu401 = 1,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_AUDIOPHILE,
+		.name = "M Audio Audiophile 24/96",
+		.model = "audiophile",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_DELTA410,
+		.name = "M Audio Delta 410",
+		.model = "delta410",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_DELTA1010LT,
+		.name = "M Audio Delta 1010LT",
+		.model = "delta1010lt",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_VX442,
+		.name = "Digigram VX442",
+		.model = "vx442",
+		.chip_init = snd_ice1712_delta_init,
+		.build_controls = snd_ice1712_delta_add_controls,
+		.no_mpu401 = 1,
 	},
 	{ } /* terminator */
 };
--- diff/sound/pci/ice1712/envy24ht.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/envy24ht.h	2004-05-27 18:34:20.000000000 +0100
@@ -209,4 +209,7 @@
 #define VT1724_MT_PDMA1_COUNT		0x76	/* word */
 
 
+unsigned char snd_vt1724_read_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr);
+void snd_vt1724_write_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr, unsigned char data);
+
 #endif /* __SOUND_VT1724_H */
--- diff/sound/pci/ice1712/ews.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/ews.c	2004-05-27 18:34:20.000000000 +0100
@@ -971,34 +971,39 @@
 /* entry point */
 struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
 	{
-		ICE1712_SUBDEVICE_EWX2496,
-		"TerraTec EWX24/96",
-		snd_ice1712_ews_init,
-		snd_ice1712_ews_add_controls,
+		.subvendor = ICE1712_SUBDEVICE_EWX2496,
+		.name = "TerraTec EWX24/96",
+		.model = "ewx2496",
+		.chip_init = snd_ice1712_ews_init,
+		.build_controls = snd_ice1712_ews_add_controls,
 	},
 	{
-		ICE1712_SUBDEVICE_EWS88MT,
-		"TerraTec EWS88MT",
-		snd_ice1712_ews_init,
-		snd_ice1712_ews_add_controls,
+		.subvendor = ICE1712_SUBDEVICE_EWS88MT,
+		.name = "TerraTec EWS88MT",
+		.model = "ews88mt",
+		.chip_init = snd_ice1712_ews_init,
+		.build_controls = snd_ice1712_ews_add_controls,
 	},
 	{
-		ICE1712_SUBDEVICE_EWS88MT_NEW,
-		"TerraTec EWS88MT",
-		snd_ice1712_ews_init,
-		snd_ice1712_ews_add_controls,
+		.subvendor = ICE1712_SUBDEVICE_EWS88MT_NEW,
+		.name = "TerraTec EWS88MT",
+		.model = "ews88mt_new",
+		.chip_init = snd_ice1712_ews_init,
+		.build_controls = snd_ice1712_ews_add_controls,
 	},
 	{
-		ICE1712_SUBDEVICE_EWS88D,
-		"TerraTec EWS88D",
-		snd_ice1712_ews_init,
-		snd_ice1712_ews_add_controls,
+		.subvendor = ICE1712_SUBDEVICE_EWS88D,
+		.name = "TerraTec EWS88D",
+		.model = "ews88d",
+		.chip_init = snd_ice1712_ews_init,
+		.build_controls = snd_ice1712_ews_add_controls,
 	},
 	{
-		ICE1712_SUBDEVICE_DMX6FIRE,
-		"TerraTec DMX6Fire",
-		snd_ice1712_ews_init,
-		snd_ice1712_ews_add_controls,
+		.subvendor = ICE1712_SUBDEVICE_DMX6FIRE,
+		.name = "TerraTec DMX6Fire",
+		.model = "dmx6fire",
+		.chip_init = snd_ice1712_ews_init,
+		.build_controls = snd_ice1712_ews_add_controls,
 	},
 	{ } /* terminator */
 };
--- diff/sound/pci/ice1712/hoontech.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/hoontech.c	2004-05-27 18:34:20.000000000 +0100
@@ -83,6 +83,7 @@
 		ICE1712_STDSP24_2_CHN4(ice->hoontech_boxbits, 0);
 	ICE1712_STDSP24_2_MIDI1(ice->hoontech_boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[3]);
 
 	ICE1712_STDSP24_1_CHN1(ice->hoontech_boxbits, 1);
 	ICE1712_STDSP24_1_CHN2(ice->hoontech_boxbits, 1);
@@ -117,7 +118,7 @@
 	up(&ice->gpio_mutex);
 }
 
-static void __devinit snd_ice1712_stdsp24_box_midi(ice1712_t *ice, int box, int master, int slave)
+static void __devinit snd_ice1712_stdsp24_box_midi(ice1712_t *ice, int box, int master)
 {
 	down(&ice->gpio_mutex);
 
@@ -128,23 +129,26 @@
 	ICE1712_STDSP24_2_MIDIIN(ice->hoontech_boxbits, 1);
 	ICE1712_STDSP24_2_MIDI1(ice->hoontech_boxbits, master);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[3]);
 
 	udelay(100);
 	
 	ICE1712_STDSP24_2_MIDIIN(ice->hoontech_boxbits, 0);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
 	
-	udelay(100);
+	mdelay(10);
 	
 	ICE1712_STDSP24_2_MIDIIN(ice->hoontech_boxbits, 1);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
 
-	udelay(100);
+	up(&ice->gpio_mutex);
+}
 
-	/* MIDI2 is direct */
-	ICE1712_STDSP24_3_MIDI2(ice->hoontech_boxbits, slave);
+static void __devinit snd_ice1712_stdsp24_midi2(ice1712_t *ice, int activate)
+{
+	down(&ice->gpio_mutex);
+	ICE1712_STDSP24_3_MIDI2(ice->hoontech_boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[3]);
-
 	up(&ice->gpio_mutex);
 }
 
@@ -204,25 +208,118 @@
 		for (chn = 0; chn < 4; chn++)
 			snd_ice1712_stdsp24_box_channel(ice, box, chn, (ice->hoontech_boxconfig[box] & (1 << chn)) ? 1 : 0);
 		snd_ice1712_stdsp24_box_midi(ice, box,
-				(ice->hoontech_boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0,
-				(ice->hoontech_boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) ? 1 : 0);
+				(ice->hoontech_boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0);
+		if (ice->hoontech_boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2)
+			snd_ice1712_stdsp24_midi2(ice, 1);
 	}
 
 	return 0;
 }
 
+/*
+ * AK4524 access
+ */
+
+/* start callback for STDSP24 with modified hardware */
+static void stdsp24_ak4524_lock(akm4xxx_t *ak, int chip)
+{
+	ice1712_t *ice = ak->private_data[0];
+	unsigned char tmp;
+	snd_ice1712_save_gpio_status(ice);
+	tmp =	ICE1712_STDSP24_SERIAL_DATA |
+		ICE1712_STDSP24_SERIAL_CLOCK |
+		ICE1712_STDSP24_AK4524_CS;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
+			  ice->gpio.direction | tmp);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
+}
+
+static int __devinit snd_ice1712_value_init(ice1712_t *ice)
+{
+	/* Hoontech STDSP24 with modified hardware */
+	static akm4xxx_t akm_stdsp24_mv __devinitdata = {
+		.num_adcs = 2,
+		.num_dacs = 2,
+		.type = SND_AK4524,
+		.ops = {
+			.lock = stdsp24_ak4524_lock
+		}
+	};
+
+	static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = {
+		.caddr = 2,
+		.cif = 1, /* CIF high */
+		.data_mask = ICE1712_STDSP24_SERIAL_DATA,
+		.clk_mask = ICE1712_STDSP24_SERIAL_CLOCK,
+		.cs_mask = ICE1712_STDSP24_AK4524_CS,
+		.cs_addr = ICE1712_STDSP24_AK4524_CS,
+		.cs_none = 0,
+		.add_flags = 0,
+	};
+
+	int err;
+	akm4xxx_t *ak;
+
+	/* set the analog DACs */
+	ice->num_total_dacs = 2;
+
+	/* set the analog ADCs */
+	ice->num_total_adcs = 2;
+	
+	/* analog section */
+	ak = ice->akm = kmalloc(sizeof(akm4xxx_t), GFP_KERNEL);
+	if (! ak)
+		return -ENOMEM;
+	ice->akm_codecs = 1;
+
+	err = snd_ice1712_akm4xxx_init(ak, &akm_stdsp24_mv, &akm_stdsp24_mv_priv, ice);
+	if (err < 0)
+		return err;
+
+	/* ak4524 controls */
+	err = snd_ice1712_akm4xxx_build_controls(ice);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int __devinit snd_ice1712_ez8_init(ice1712_t *ice)
+{
+	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);
+	return 0;
+}
+
 
 /* entry point */
 struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
 	{
-		ICE1712_SUBDEVICE_STDSP24,
-		"Hoontech SoundTrack Audio DSP24",
-		snd_ice1712_hoontech_init,
+		.subvendor = ICE1712_SUBDEVICE_STDSP24,
+		.name = "Hoontech SoundTrack Audio DSP24",
+		.model = "dsp24",
+		.chip_init = snd_ice1712_hoontech_init,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_STDSP24_VALUE,	/* a dummy id */
+		.name = "Hoontech SoundTrack Audio DSP24 Value",
+		.model = "dsp24_value",
+		.chip_init = snd_ice1712_value_init,
+	},
+	{
+		.subvendor = ICE1712_SUBDEVICE_STDSP24_MEDIA7_1,
+		.name = "Hoontech STA DSP24 Media 7.1",
+		.model = "dsp24_71",
+		.chip_init = snd_ice1712_hoontech_init,
 	},
 	{
-		ICE1712_SUBDEVICE_STDSP24_MEDIA7_1,
-		"Hoontech STA DSP24 Media 7.1",
-		snd_ice1712_hoontech_init,
+		.subvendor = ICE1712_SUBDEVICE_EVENT_EZ8,	/* a dummy id */
+		.name = "Event Electronics EZ8",
+		.model = "ez8",
+		.chip_init = snd_ice1712_ez8_init,
 	},
 	{ } /* terminator */
 };
--- diff/sound/pci/ice1712/hoontech.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/hoontech.h	2004-05-27 18:34:20.000000000 +0100
@@ -25,12 +25,15 @@
  */      
 
 #define  HOONTECH_DEVICE_DESC \
-	"{Hoontech SoundTrack DSP 24}," \
-	"{Hoontech SoundTrack DSP 24 Value}," \
-	"{Hoontech SoundTrack DSP 24 Media 7.1}," \
+	"{Hoontech,SoundTrack DSP 24}," \
+	"{Hoontech,SoundTrack DSP 24 Value}," \
+	"{Hoontech,SoundTrack DSP 24 Media 7.1}," \
+	"{Event Electronics,EZ8},"
 
 #define ICE1712_SUBDEVICE_STDSP24		0x12141217	/* Hoontech SoundTrack Audio DSP 24 */
+#define ICE1712_SUBDEVICE_STDSP24_VALUE		0x00010010	/* A dummy id for Hoontech SoundTrack Audio DSP 24 Value */
 #define ICE1712_SUBDEVICE_STDSP24_MEDIA7_1	0x16141217	/* Hoontech ST Audio DSP24 Media 7.1 */
+#define ICE1712_SUBDEVICE_EVENT_EZ8		0x00010001	/* A dummy id for EZ8 */
 
 extern struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
 
@@ -65,4 +68,10 @@
 #define ICE1712_STDSP24_BOX_MIDI1	(1<<8)
 #define ICE1712_STDSP24_BOX_MIDI2	(1<<9)
 
+/* Hoontech SoundTrack Audio DSP 24 Value definitions for modified hardware */
+
+#define ICE1712_STDSP24_AK4524_CS	0x03	/* AK4524 chip select; low = active */
+#define ICE1712_STDSP24_SERIAL_DATA	0x0c	/* ak4524 data */
+#define ICE1712_STDSP24_SERIAL_CLOCK	0x30	/* ak4524 clock */
+
 #endif /* __SOUND_HOONTECH_H */
--- diff/sound/pci/ice1712/ice1712.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/ice1712.c	2004-05-27 18:34:20.000000000 +0100
@@ -41,6 +41,9 @@
  *  2003.02.20  Taksahi Iwai <tiwai@suse.de>
  *	Split vt1724 part to an independent driver.
  *	The GPIO is accessed through the callback functions now.
+ *
+ * 2004.03.31 Doug McLain <nostar@comcast.net>
+ *    Added support for Event Electronics EZ8 card to hoontech.c.
  */
 
 
@@ -51,11 +54,11 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/cs8427.h>
 #include <sound/info.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <sound/asoundef.h>
@@ -81,24 +84,28 @@
 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 */
-static int omni[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};	/* Delta44 & 66 Omni I/O support */
+static char *model[SNDRV_CARDS];
+static int omni[SNDRV_CARDS];	/* Delta44 & 66 Omni I/O support */
 static int cs8427_timeout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 500}; /* CS8427 S/PDIF transciever reset timeout value in msec */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for ICE1712 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable ICE1712 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(omni, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(omni, bool, boot_devs, 0444);
 MODULE_PARM_DESC(omni, "Enable Midiman M-Audio Delta Omni I/O support.");
 MODULE_PARM_SYNTAX(omni, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
-MODULE_PARM(cs8427_timeout, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(cs8427_timeout, int, boot_devs, 0444);
 MODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec resolution.");
 MODULE_PARM_SYNTAX(cs8427_timeout, SNDRV_ENABLED ", allows:{{1,1000}},default=500,skill:advanced");
+module_param_array(model, charp, boot_devs, 0444);
+MODULE_PARM_DESC(model, "Use the given board model.");
 
 #ifndef PCI_VENDOR_ID_ICE
 #define PCI_VENDOR_ID_ICE		0x1412
@@ -1898,6 +1905,74 @@
 	.put = snd_ice1712_pro_internal_clock_put
 };
 
+static int snd_ice1712_pro_internal_clock_default_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 */
+		// "IEC958 Input",	/* 13: -- */
+	};
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 13;
+	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_ice1712_pro_internal_clock_default_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	int val;
+	static unsigned int xrate[13] = {
+		8000, 9600, 11025, 12000, 1600, 22050, 24000,
+		32000, 44100, 48000, 64000, 88200, 96000
+	};
+
+	for (val = 0; val < 13; val++) {
+		if (xrate[val] == PRO_RATE_DEFAULT)
+			break;
+	}
+
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+static int snd_ice1712_pro_internal_clock_default_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	static unsigned int xrate[13] = {
+		8000, 9600, 11025, 12000, 1600, 22050, 24000,
+		32000, 44100, 48000, 64000, 88200, 96000
+	};
+	unsigned char oval;
+	int change = 0;
+
+	oval = PRO_RATE_DEFAULT;
+	PRO_RATE_DEFAULT = xrate[ucontrol->value.integer.value[0] % 13];
+	change = PRO_RATE_DEFAULT != oval;
+
+	return change;
+}
+
+static snd_kcontrol_new_t snd_ice1712_pro_internal_clock_default __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Multi Track Internal Clock Default",
+	.info = snd_ice1712_pro_internal_clock_default_info,
+	.get = snd_ice1712_pro_internal_clock_default_get,
+	.put = snd_ice1712_pro_internal_clock_default_put
+};
+
 static int snd_ice1712_pro_rate_locking_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -2213,6 +2288,16 @@
  *
  */
 
+/*
+ * list of available boards
+ */
+static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+	snd_ice1712_hoontech_cards,
+	snd_ice1712_delta_cards,
+	snd_ice1712_ews_cards,
+	0,
+};
+
 static unsigned char __devinit snd_ice1712_read_i2c(ice1712_t *ice,
 						 unsigned char dev,
 						 unsigned char addr)
@@ -2225,7 +2310,7 @@
 	return inb(ICEREG(ice, I2C_DATA));
 }
 
-static int __devinit snd_ice1712_read_eeprom(ice1712_t *ice)
+static int __devinit snd_ice1712_read_eeprom(ice1712_t *ice, const char *modelname)
 {
 	int dev = 0xa0;		/* EEPROM device address */
 	unsigned int i, size;
@@ -2234,10 +2319,23 @@
 		snd_printk("ICE1712 has not detected EEPROM\n");
 		return -EIO;
 	}
-	ice->eeprom.subvendor = (snd_ice1712_read_i2c(ice, dev, 0x00) << 0) |
-				(snd_ice1712_read_i2c(ice, dev, 0x01) << 8) | 
-				(snd_ice1712_read_i2c(ice, dev, 0x02) << 16) | 
-				(snd_ice1712_read_i2c(ice, dev, 0x03) << 24);
+	if (modelname && *modelname) {
+		struct snd_ice1712_card_info **tbl, *c;
+		for (tbl = card_tables; *tbl; tbl++) {
+			for (c = *tbl; c->subvendor; c++) {
+				if (c->model && !strcmp(modelname, c->model)) {
+					/* use the given subvendor */
+					printk(KERN_INFO "ice1712: Using board model %s\n", c->name);
+					ice->eeprom.subvendor = c->subvendor;
+					break;
+				}
+			}
+		}
+	} else
+		ice->eeprom.subvendor = (snd_ice1712_read_i2c(ice, dev, 0x00) << 0) |
+			(snd_ice1712_read_i2c(ice, dev, 0x01) << 8) | 
+			(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 < 6)
 		ice->eeprom.size = 32; /* FIXME: any cards without the correct size? */
@@ -2335,6 +2433,9 @@
 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_internal_clock, ice));
 	if (err < 0)
 		return err;
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_internal_clock_default, ice));
+	if (err < 0)
+		return err;
 
 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_rate_locking, ice));
 	if (err < 0)
@@ -2407,6 +2508,7 @@
 
 static int __devinit snd_ice1712_create(snd_card_t * card,
 					struct pci_dev *pci,
+					const char *modelname,
 					int omni,
 					int cs8427_timeout,
 					ice1712_t ** r_ice1712)
@@ -2491,7 +2593,7 @@
 	
 	ice->irq = pci->irq;
 
-	if (snd_ice1712_read_eeprom(ice) < 0) {
+	if (snd_ice1712_read_eeprom(ice, modelname) < 0) {
 		snd_ice1712_free(ice);
 		return -EIO;
 	}
@@ -2526,14 +2628,6 @@
 
 static struct snd_ice1712_card_info no_matched __devinitdata;
 
-static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
-	snd_ice1712_hoontech_cards,
-	snd_ice1712_delta_cards,
-	snd_ice1712_ews_cards,
-	0,
-};
-
-
 static int __devinit snd_ice1712_probe(struct pci_dev *pci,
 				       const struct pci_device_id *pci_id)
 {
@@ -2557,7 +2651,7 @@
 	strcpy(card->driver, "ICE1712");
 	strcpy(card->shortname, "ICEnsemble ICE1712");
 	
-	if ((err = snd_ice1712_create(card, pci, omni[dev], cs8427_timeout[dev], &ice)) < 0) {
+	if ((err = snd_ice1712_create(card, pci, model[dev], omni[dev], cs8427_timeout[dev], &ice)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
@@ -2566,6 +2660,8 @@
 		for (c = *tbl; c->subvendor; c++) {
 			if (c->subvendor == ice->eeprom.subvendor) {
 				strcpy(card->shortname, c->name);
+				if (c->driver) /* specific driver? */
+					strcpy(card->driver, c->driver);
 				if (c->chip_init) {
 					if ((err = c->chip_init(ice)) < 0) {
 						snd_card_free(card);
@@ -2659,15 +2755,7 @@
 
 static int __init alsa_card_ice1712_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "ICE1712 soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_ice1712_exit(void)
@@ -2677,24 +2765,3 @@
 
 module_init(alsa_card_ice1712_init)
 module_exit(alsa_card_ice1712_exit)
-
-#ifndef MODULE
-
-/* format is: snd-ice1712=enable,index,id */
-
-static int __init alsa_card_ice1712_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-ice1712=", alsa_card_ice1712_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/ice1712/ice1712.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/ice1712.h	2004-05-27 18:34:20.000000000 +0100
@@ -329,6 +329,10 @@
 	unsigned int pro_volumes[20];
 	unsigned int omni: 1;		/* Delta Omni I/O */
 	unsigned int vt1724: 1;
+	unsigned int vt1720: 1;
+	unsigned int has_spdif: 1;	/* VT1720/4 - has SPDIF I/O */
+	unsigned int force_pdma4: 1;	/* VT1720/4 - PDMA4 as non-spdif */
+	unsigned int force_rdma1: 1;	/* VT1720/4 - RDMA1 as non-spdif */
 	unsigned int num_total_dacs;	/* total DACs */
 	unsigned int num_total_adcs;	/* total ADCs */
 	unsigned char hoontech_boxbits[4];
@@ -460,6 +464,8 @@
 struct snd_ice1712_card_info {
 	unsigned int subvendor;
 	char *name;
+	char *model;
+	char *driver;
 	int (*chip_init)(ice1712_t *);
 	int (*build_controls)(ice1712_t *);
 	int no_mpu401: 1;
--- diff/sound/pci/ice1712/ice1724.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/ice1724.c	2004-05-27 18:34:20.000000000 +0100
@@ -1,5 +1,6 @@
 /*
  *   ALSA driver for VT1724 ICEnsemble ICE1724 / VIA VT1724 (Envy24HT)
+ *                   VIA VT1720 (Envy24PT)
  *
  *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
  *                    2002 James Stafford <jstafford@ampltd.com>
@@ -28,10 +29,10 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.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>
@@ -43,35 +44,39 @@
 #include "amp.h"
 #include "revo.h"
 #include "aureon.h"
-#include "prodigy.h"
 
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("ICEnsemble ICE1724 (Envy24HT)");
+MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
 MODULE_DEVICES("{"
 	       REVO_DEVICE_DESC
 	       AMP_AUDIO2000_DEVICE_DESC
 	       AUREON_DEVICE_DESC
-	       PRODIGY_DEVICE_DESC
+		"{VIA,VT1720},"
 		"{VIA,VT1724},"
 		"{ICEnsemble,Generic ICE1724},"
-		"{ICEnsemble,Generic Envy24HT}}");
+		"{ICEnsemble,Generic Envy24HT}"
+		"{ICEnsemble,Generic Envy24PT}}");
 
 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 */
+static char *model[SNDRV_CARDS];
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 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_param_array(id, charp, boot_devs, 0444);
 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_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable ICE1724 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+module_param_array(model, charp, boot_devs, 0444);
+MODULE_PARM_DESC(model, "Use the given board model.");
 
 #ifndef PCI_VENDOR_ID_ICE
 #define PCI_VENDOR_ID_ICE		0x1412
@@ -80,6 +85,7 @@
 #define PCI_DEVICE_ID_VT1724		0x1724
 #endif
 
+/* Both VT1720 and VT1724 have the same PCI IDs */
 static struct pci_device_id snd_vt1724_ids[] = {
 	{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	{ 0, }
@@ -228,6 +234,17 @@
 			status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX);
 		}
 		if (status & VT1724_IRQ_MTPCM) {
+			/*
+			 * Multi-track PCM
+			 * PCM assignment are:
+			 * Playback DMA0 (M/C) = playback_pro_substream
+			 * Playback DMA1 = playback_con_substream_ds[0]
+			 * Playback DMA2 = playback_con_substream_ds[1]
+			 * Playback DMA3 = playback_con_substream_ds[2]
+			 * Playback DMA4 (SPDIF) = playback_con_substream
+			 * Record DMA0 = capture_pro_substream
+			 * Record DMA1 = capture_con_substream
+			 */
 			unsigned char mtstat = inb(ICEMT1724(ice, IRQ));
 			if (mtstat & VT1724_MULTI_PDMA0) {
 				if (ice->playback_pro_substream)
@@ -288,6 +305,12 @@
 	.mask = 0,
 };
 
+static snd_pcm_hw_constraint_list_t hw_constraints_rates_48 = {
+	.count = ARRAY_SIZE(rates) - 5, /* up to 48000 */
+	.list = rates,
+	.mask = 0,
+};
+
 static snd_pcm_hw_constraint_list_t hw_constraints_rates_192 = {
 	.count = ARRAY_SIZE(rates),
 	.list = rates,
@@ -423,6 +446,15 @@
 		if (ice->akm[i].ops.set_rate_val)
 			ice->akm[i].ops.set_rate_val(&ice->akm[i], rate);
 	}
+
+	/* set up AC97 registers if needed */
+	if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) && ice->ac97) {
+		snd_ac97_set_rate(ice->ac97, AC97_PCM_FRONT_DAC_RATE, rate);
+		snd_ac97_set_rate(ice->ac97, AC97_PCM_SURR_DAC_RATE, rate);
+		snd_ac97_set_rate(ice->ac97, AC97_PCM_LFE_DAC_RATE, rate);
+		snd_ac97_set_rate(ice->ac97, AC97_SPDIF, rate);
+		snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, rate);
+	}
 }
 
 static int snd_vt1724_pcm_hw_params(snd_pcm_substream_t * substream,
@@ -435,6 +467,7 @@
 	down(&ice->open_mutex);
 	/* mark surround channels */
 	if (substream == ice->playback_pro_substream) {
+		/* PDMA0 can be multi-channel up to 8 */
 		chs = chs / 2 - 1;
 		for (i = 0; i < chs; i++) {
 			if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) {
@@ -449,6 +482,7 @@
 		}
 	} else {
 		for (i = 0; i < 3; i++) {
+			/* check individual playback stream */
 			if (ice->playback_con_substream_ds[i] == substream) {
 				if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) {
 					up(&ice->open_mutex);
@@ -609,7 +643,7 @@
 				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
 	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
 	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_192000,
-	.rate_min =		4000,
+	.rate_min =		8000,
 	.rate_max =		192000,
 	.channels_min =		2,
 	.channels_max =		8,
@@ -620,6 +654,25 @@
 	.periods_max =		1024,
 };
 
+static snd_pcm_hardware_t snd_vt1724_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_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+	.rate_min =		32000,
+	.rate_max =		48000,
+	.channels_min =		2,
+	.channels_max =		2,
+	.buffer_bytes_max =	(1UL << 18),	/* 16bits dword */
+	.period_bytes_min =	2 * 4 * 2,
+	.period_bytes_max =	(1UL << 18),
+	.periods_min =		2,
+	.periods_max =		1024,
+};
+
 static snd_pcm_hardware_t snd_vt1724_2ch_stereo =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
@@ -628,7 +681,7 @@
 				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
 	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
 	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_192000,
-	.rate_min =		4000,
+	.rate_min =		8000,
 	.rate_max =		192000,
 	.channels_min =		2,
 	.channels_max =		2,
@@ -639,6 +692,41 @@
 	.periods_max =		1024,
 };
 
+/*
+ * set rate constraints
+ */
+static int set_rate_constraints(ice1712_t *ice, snd_pcm_substream_t *substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	if (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) {
+		/* I2S */
+		if (ice->eeprom.data[ICE_EEP2_I2S] & 0x08)
+			return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192);
+		else {
+			runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000;
+			runtime->hw.rate_max = 96000;
+			return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
+		}
+	} else if (ice->ac97) {
+		/* ACLINK */
+		int ratec;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ratec = AC97_RATES_FRONT_DAC;
+		else
+			ratec = AC97_RATES_ADC;
+		runtime->hw.rates = ice->ac97->rates[ratec];
+		runtime->hw.rate_max = 48000;
+		if (runtime->hw.rates == SNDRV_PCM_RATE_48000) {
+			runtime->hw.rate_min = 48000;
+			return 0;
+		} else {
+			runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000;
+			return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_48);
+		}
+	}
+	return 0;
+}
+
 /* multi-channel playback needs alignment 8x32bit regarless of the channels
  * actually used
  */
@@ -655,12 +743,7 @@
 	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);
-
+	set_rate_constraints(ice, substream);
 	down(&ice->open_mutex);
 	/* calculate the currently available channels */
 	for (chs = 0; chs < 3; chs++) {
@@ -689,11 +772,7 @@
 	runtime->hw = snd_vt1724_2ch_stereo;
 	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);
+	set_rate_constraints(ice, substream);
 	return 0;
 }
 
@@ -812,11 +891,13 @@
 
 	runtime->private_data = (void*)VT1724_PDMA4_START; /* irq/status/trigger bit */
 	ice->playback_con_substream = substream;
-	runtime->hw = snd_vt1724_2ch_stereo;
+	if (ice->force_pdma4) {
+		runtime->hw = snd_vt1724_2ch_stereo;
+		set_rate_constraints(ice, substream);
+	} else
+		runtime->hw = snd_vt1724_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_192);
 	return 0;
 }
 
@@ -838,10 +919,13 @@
 
 	runtime->private_data = (void*)VT1724_RDMA1_START; /* irq/status/trigger bit */
 	ice->capture_con_substream = substream;
-	runtime->hw = snd_vt1724_2ch_stereo;
+	if (ice->force_rdma1) {
+		runtime->hw = snd_vt1724_2ch_stereo;
+		set_rate_constraints(ice, substream);
+	} else
+		runtime->hw = snd_vt1724_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;
 }
 
@@ -881,22 +965,31 @@
 
 static int __devinit snd_vt1724_pcm_spdif(ice1712_t * ice, int device)
 {
+	char *name;
 	snd_pcm_t *pcm;
 	int play, capt;
 	int err;
 
-	if (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_OUT_INT)
+	if (ice->force_pdma4 ||
+	    (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_OUT_INT)) {
 		play = 1;
-	else
+		ice->has_spdif = 1;
+	} else
 		play = 0;
-	if (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_IN)
+	if (ice->force_rdma1 ||
+	    (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_IN)) {
 		capt = 1;
-	else
+		ice->has_spdif = 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 (ice->force_pdma4 || ice->force_rdma1)
+		name = "ICE1724 Secondary";
+	else
+		name = "IEC1724 IEC958";
+	err = snd_pcm_new(ice->card, name, device, play, capt, &pcm);
 	if (err < 0)
 		return err;
 
@@ -909,7 +1002,7 @@
 
 	pcm->private_data = ice;
 	pcm->info_flags = 0;
-	strcpy(pcm->name, "ICE1724 IEC958");
+	strcpy(pcm->name, name);
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(ice->pci), 64*1024, 64*1024);
@@ -983,8 +1076,7 @@
 	runtime->hw = snd_vt1724_2ch_stereo;
 	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_192);
+	set_rate_constraints(ice, substream);
 	return 0;
 }
 
@@ -1723,7 +1815,6 @@
 	snd_vt1724_revo_cards,
 	snd_vt1724_amp_cards, 
 	snd_vt1724_aureon_cards,
-	snd_vt1724_prodigy_cards,
 	0,
 };
 
@@ -1731,9 +1822,7 @@
 /*
  */
 
-static unsigned char __devinit snd_vt1724_read_i2c(ice1712_t *ice,
-						 unsigned char dev,
-						 unsigned char addr)
+unsigned char snd_vt1724_read_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr)
 {
 	long t = 0x10000;
 
@@ -1743,49 +1832,71 @@
 	return inb(ICEREG1724(ice, I2C_DATA));
 }
 
-static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice)
+void snd_vt1724_write_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr, unsigned char data)
 {
-	int dev = 0xa0;		/* EEPROM device address */
+	long t = 0x10000;
+
+	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
+	outb(data, ICEREG1724(ice, I2C_DATA));
+	outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
+	while (t-- > 0 && (inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY)) ;
+}
+
+static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice, const char *modelname)
+{
+	const int dev = 0xa0;		/* EEPROM device address */
 	unsigned int i, size;
 	struct snd_ice1712_card_info **tbl, *c;
 
-	if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) == 0) {
-		snd_printk(KERN_WARNING "ICE1724 has not detected EEPROM\n");
-		// return -EIO;
-	}
-	ice->eeprom.subvendor = (snd_vt1724_read_i2c(ice, dev, 0x00) << 0) |
+	if (! modelname || ! *modelname) {
+		ice->eeprom.subvendor = 0;
+		if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) != 0)
+			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);
-
-	/* if the EEPROM is given by the driver, use it */
+		if (ice->eeprom.subvendor == 0 || ice->eeprom.subvendor == (unsigned int)-1) {
+			/* invalid subvendor from EEPROM, try the PCI subststem ID instead */
+			u16 vendor, device;
+			pci_read_config_word(ice->pci, PCI_SUBSYSTEM_VENDOR_ID, &vendor);
+			pci_read_config_word(ice->pci, PCI_SUBSYSTEM_ID, &device);
+			ice->eeprom.subvendor = ((unsigned int)swab16(vendor) << 16) | swab16(device);
+			if (ice->eeprom.subvendor == 0 || ice->eeprom.subvendor == (unsigned int)-1) {
+				printk(KERN_ERR "ice1724: No valid ID is found\n");
+				return -ENXIO;
+			}
+		}
+	}
 	for (tbl = card_tables; *tbl; tbl++) {
 		for (c = *tbl; c->subvendor; c++) {
-			if (c->subvendor == ice->eeprom.subvendor) {
-				if (! c->eeprom_size || ! c->eeprom_data)
-					goto found;
-				snd_printdd("using the defined eeprom..\n");
-				ice->eeprom.version = 2;
-				ice->eeprom.size = c->eeprom_size + 6;
-				memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size);
-				goto read_skipped;
-			}
+			if (modelname && c->model && ! strcmp(modelname, c->model)) {
+				printk(KERN_INFO "ice1724: Using board model %s\n", c->name);
+				ice->eeprom.subvendor = c->subvendor;
+			} else if (c->subvendor != ice->eeprom.subvendor)
+				continue;
+			if (! c->eeprom_size || ! c->eeprom_data)
+				goto found;
+			/* if the EEPROM is given by the driver, use it */
+			snd_printdd("using the defined eeprom..\n");
+			ice->eeprom.version = 2;
+			ice->eeprom.size = c->eeprom_size + 6;
+			memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size);
+			goto read_skipped;
 		}
 	}
+	printk(KERN_WARNING "ice1724: No matching model found for ID 0x%x\n", ice->eeprom.subvendor);
 
  found:
 	ice->eeprom.size = snd_vt1724_read_i2c(ice, dev, 0x04);
 	if (ice->eeprom.size < 6)
 		ice->eeprom.size = 32;
 	else if (ice->eeprom.size > 32) {
-		snd_printk("invalid EEPROM (size = %i)\n", ice->eeprom.size);
+		printk(KERN_ERR "ice1724: 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;
-	}
+	if (ice->eeprom.version != 2)
+		printk(KERN_WARNING "ice1724: Invalid EEPROM version %i\n", ice->eeprom.version);
 	size = ice->eeprom.size - 6;
 	for (i = 0; i < size; i++)
 		ice->eeprom.data[i] = snd_vt1724_read_i2c(ice, dev, i + 6);
@@ -1819,6 +1930,9 @@
 
 	outb(0, ICEREG1724(ice, POWERDOWN));
 
+	/* read back to check the availability of SPDIF out */
+	ice->eeprom.data[ICE_EEP2_SPDIF] = inb(ICEREG1724(ice, SPDIF_CFG));
+
 	return 0;
 }
 
@@ -1880,7 +1994,10 @@
 
 	if (ice->num_total_dacs > 0) {
 		snd_kcontrol_new_t tmp = snd_vt1724_mixer_pro_analog_route;
-		tmp.count = ice->num_total_dacs;
+		if (ice->vt1720)
+			tmp.count = 2;
+		else
+			tmp.count = ice->num_total_dacs;
 		err = snd_ctl_add(ice->card, snd_ctl_new1(&tmp, ice));
 		if (err < 0)
 			return err;
@@ -1927,6 +2044,7 @@
 
 static int __devinit snd_vt1724_create(snd_card_t * card,
 				       struct pci_dev *pci,
+				       const char *modelname,
 				       ice1712_t ** r_ice1712)
 {
 	ice1712_t *ice;
@@ -1982,7 +2100,7 @@
 
 	ice->irq = pci->irq;
 
-	if (snd_vt1724_read_eeprom(ice) < 0) {
+	if (snd_vt1724_read_eeprom(ice, modelname) < 0) {
 		snd_vt1724_free(ice);
 		return -EIO;
 	}
@@ -2041,7 +2159,7 @@
 	strcpy(card->driver, "ICE1724");
 	strcpy(card->shortname, "ICEnsemble ICE1724");
 	
-	if ((err = snd_vt1724_create(card, pci, &ice)) < 0) {
+	if ((err = snd_vt1724_create(card, pci, model[dev], &ice)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
@@ -2050,6 +2168,8 @@
 		for (c = *tbl; c->subvendor; c++) {
 			if (c->subvendor == ice->eeprom.subvendor) {
 				strcpy(card->shortname, c->name);
+				if (c->driver) /* specific driver? */
+					strcpy(card->driver, c->driver);
 				if (c->chip_init) {
 					if ((err = c->chip_init(ice)) < 0) {
 						snd_card_free(card);
@@ -2088,7 +2208,7 @@
 		return err;
 	}
 
-	if (ice->pcm) { /* has SPDIF I/O */
+	if (ice->pcm && ice->has_spdif) { /* has SPDIF I/O */
 		if ((err = snd_vt1724_spdif_build_controls(ice)) < 0) {
 			snd_card_free(card);
 			return err;
@@ -2141,15 +2261,7 @@
 
 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;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_ice1724_exit(void)
@@ -2159,24 +2271,3 @@
 
 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/sound/pci/ice1712/revo.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/revo.c	2004-05-27 18:34:20.000000000 +0100
@@ -171,10 +171,11 @@
 /* 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,
+		.subvendor = VT1724_SUBDEVICE_REVOLUTION71,
+		.name = "M Audio Revolution-7.1",
+		.model = "revo71",
+		.chip_init = revo_init,
+		.build_controls = revo_add_controls,
 	},
 	{ } /* terminator */
 };
--- diff/sound/pci/intel8x0.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/intel8x0.c	2004-05-27 18:34:20.000000000 +0100
@@ -34,12 +34,12 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 /* for 440MX workaround */
 #include <asm/pgtable.h>
@@ -81,29 +81,30 @@
 #ifdef SUPPORT_MIDI
 static int mpu_port[SNDRV_CARDS]; /* disabled */
 #endif
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Intel i8x0 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ac97_clock, int, boot_devs, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
 MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0");
-MODULE_PARM(ac97_quirk, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ac97_quirk, int, boot_devs, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,4}},dialog:list,default:-1");
 #ifdef SUPPORT_JOYSTICK
-MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick, bool, boot_devs, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard.");
 MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 #endif
 #ifdef SUPPORT_MIDI
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mpu_port, int, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU401 port # for Intel i8x0 driver.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x300}},dialog:list");
 #endif
@@ -235,6 +236,7 @@
 #define   ICH_P2INT		0x02000000	/* ICH4: PCM2-In interrupt */
 #define   ICH_M2INT		0x01000000	/* ICH4: Mic2-In interrupt */
 #define   ICH_SAMPLE_CAP	0x00c00000	/* ICH4: sample capability bits (RO) */
+#define   ICH_SAMPLE_16_20	0x00400000	/* ICH4: 16- and 20-bit samples */
 #define   ICH_MULTICHAN_CAP	0x00300000	/* ICH4: multi-channel capability bits (RO) */
 #define   ICH_MD3		0x00020000	/* modem power down semaphore */
 #define   ICH_AD3		0x00010000	/* audio power down semaphore */
@@ -378,6 +380,7 @@
         unsigned int fragsize;
         unsigned int fragsize1;
         unsigned int position;
+	unsigned int pos_shift;
         int frags;
         int lvi;
         int lvi_frag;
@@ -441,10 +444,9 @@
 	struct snd_dma_buffer bdbars;
 	u32 int_sta_reg;		/* interrupt status register */
 	u32 int_sta_mask;		/* interrupt status mask */
-	unsigned int pcm_pos_shift;
-	
+
 #ifdef CONFIG_PM
-	int in_suspend;
+	u32 pci_state[64 / sizeof(u32)];
 #endif
 };
 
@@ -719,10 +721,10 @@
 		for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 4) {
 			bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf);
 			bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
-						     ichdev->fragsize1 >> chip->pcm_pos_shift);
+						     ichdev->fragsize1 >> ichdev->pos_shift);
 			bdbar[idx + 2] = cpu_to_le32(ichdev->physbuf + (ichdev->size >> 1));
 			bdbar[idx + 3] = cpu_to_le32(0x80000000 | /* interrupt on completion */
-						     ichdev->fragsize1 >> chip->pcm_pos_shift);
+						     ichdev->fragsize1 >> ichdev->pos_shift);
 		}
 		ichdev->frags = 2;
 	} else {
@@ -731,7 +733,7 @@
 		for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 2) {
 			bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + (((idx >> 1) * ichdev->fragsize) % ichdev->size));
 			bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
-						     ichdev->fragsize >> chip->pcm_pos_shift);
+						     ichdev->fragsize >> ichdev->pos_shift);
 			// printk("bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
 		}
 		ichdev->frags = ichdev->size / ichdev->fragsize;
@@ -773,11 +775,14 @@
 static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev)
 {
 	unsigned long port = ichdev->reg_offset;
-	int civ, i, step;
+	int status, civ, i, step;
 	int ack = 0;
 
+	status = igetbyte(chip, port + ichdev->roff_sr);
 	civ = igetbyte(chip, port + ICH_REG_OFF_CIV);
-	if (civ == ichdev->civ) {
+	if (!(status & ICH_BCIS)) {
+		step = 0;
+	} else if (civ == ichdev->civ) {
 		// snd_printd("civ same %d\n", civ);
 		step = 1;
 		ichdev->civ++;
@@ -811,7 +816,8 @@
 		snd_pcm_period_elapsed(ichdev->substream);
 		spin_lock(&chip->reg_lock);
 	}
-	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+	iputbyte(chip, port + ichdev->roff_sr,
+		 status & (ICH_FIFOE | ICH_BCIS | ICH_LVBCI));
 }
 
 static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -981,7 +987,8 @@
 	return snd_pcm_lib_free_pages(substream);
 }
 
-static void snd_intel8x0_setup_multi_channels(intel8x0_t *chip, int channels)
+static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
+				       int channels, int sample_bits)
 {
 	unsigned int cnt;
 	switch (chip->device_type) {
@@ -1005,7 +1012,7 @@
 		break;
 	default:
 		cnt = igetdword(chip, ICHREG(GLOB_CNT));
-		cnt &= ~ICH_PCM_246_MASK;
+		cnt &= ~(ICH_PCM_246_MASK | ICH_PCM_20BIT);
 		if (chip->multi4 && channels == 4)
 			cnt |= ICH_PCM_4;
 		else if (chip->multi6 && channels == 6)
@@ -1016,6 +1023,9 @@
 			 */
 			iputdword(chip, ICHREG(GLOB_CNT), (cnt & 0xcfffff));
 			mdelay(50); /* grrr... */
+		} else if (chip->device_type == DEVICE_INTEL_ICH4) {
+			if (sample_bits > 16)
+				cnt |= ICH_PCM_20BIT;
 		}
 		iputdword(chip, ICHREG(GLOB_CNT), cnt);
 		break;
@@ -1033,8 +1043,12 @@
 	ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
 	if (ichdev->ichd == ICHD_PCMOUT) {
 		spin_lock(&chip->reg_lock);
-		snd_intel8x0_setup_multi_channels(chip, runtime->channels);
+		snd_intel8x0_setup_pcm_out(chip, runtime->channels,
+					   runtime->sample_bits);
 		spin_unlock(&chip->reg_lock);
+		if (chip->device_type == DEVICE_INTEL_ICH4) {
+			ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
+		}
 	}
 	snd_intel8x0_setup_periods(chip, ichdev);
 	return 0;
@@ -1047,7 +1061,7 @@
 	unsigned long flags;
 	size_t ptr1, ptr;
 
-	ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift;
+	ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << ichdev->pos_shift;
 	if (ptr1 != 0)
 		ptr = ichdev->fragsize1 - ptr1;
 	else
@@ -1142,6 +1156,8 @@
 		runtime->hw.channels_max = 4;
 		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels4);
 	}
+	if (chip->smp20bit)
+		runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE;
 	return 0;
 }
 
@@ -1844,6 +1860,7 @@
 	memset(&ac97, 0, sizeof(ac97));
 	ac97.private_data = chip;
 	ac97.private_free = snd_intel8x0_mixer_free_ac97;
+	ac97.scaps = AC97_SCAP_SKIP_MODEM;
 	if (chip->device_type != DEVICE_ALI) {
 		glob_sta = igetdword(chip, ICHREG(GLOB_STA));
 		bus.write = snd_intel8x0_codec_write;
@@ -1892,7 +1909,8 @@
 	for (i = 0; i < codecs; i++) {
 		ac97.num = i;
 		if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) {
-			snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i);
+			if (err != -EACCES)
+				snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i);
 			if (i == 0)
 				goto __err;
 			continue;
@@ -1946,6 +1964,10 @@
 		if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE))
 			chip->multi6 = 1;
 	}
+	if (chip->device_type == DEVICE_INTEL_ICH4) {
+		if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20)
+			chip->smp20bit = 1;
+	}
 	if (chip->device_type == DEVICE_NFORCE) {
 		/* 48kHz only */
 		chip->ichd[spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000;
@@ -2184,74 +2206,54 @@
 /*
  * power management
  */
-static void intel8x0_suspend(intel8x0_t *chip)
+static int intel8x0_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->pm_private_data, return -EINVAL);
 	int i;
 
-	if (chip->in_suspend ||
-	    card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
-
-	chip->in_suspend = 1;
 	for (i = 0; i < chip->pcm_devs; i++)
 		snd_pcm_suspend_all(chip->pcm[i]);
+	for (i = 0; i < 3; i++)
+		if (chip->ac97[i])
+			snd_ac97_suspend(chip->ac97[i]);
+	pci_save_state(chip->pci, chip->pci_state);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void intel8x0_resume(intel8x0_t *chip)
+static int intel8x0_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->pm_private_data, return -EINVAL);
 	int i;
 
-	if (! chip->in_suspend ||
-	    card->power_state == SNDRV_CTL_POWER_D0)
-		return;
-
+	pci_restore_state(chip->pci, chip->pci_state);
 	pci_enable_device(chip->pci);
 	pci_set_master(chip->pci);
 	snd_intel8x0_chip_init(chip, 0);
+
+	/* refill nocache */
+	if (chip->fix_nocache)
+		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
+
 	for (i = 0; i < 3; i++)
 		if (chip->ac97[i])
 			snd_ac97_resume(chip->ac97[i]);
 
-	chip->in_suspend = 0;
-	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_intel8x0_suspend(struct pci_dev *dev, u32 state)
-{
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO);
-	intel8x0_suspend(chip);
-	return 0;
-}
-static int snd_intel8x0_resume(struct pci_dev *dev)
-{
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO);
-	intel8x0_resume(chip);
-	return 0;
-}
-
-/* callback */
-static int snd_intel8x0_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->power_state_private_data, return -ENXIO);
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		intel8x0_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		intel8x0_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
+	/* refill nocache */
+	if (chip->fix_nocache) {
+		for (i = 0; i < chip->bdbars_count; i++) {
+			ichdev_t *ichdev = &chip->ichd[i];
+			if (ichdev->substream) {
+				snd_pcm_runtime_t *runtime = ichdev->substream->runtime;
+				if (runtime->dma_area)
+					fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
+			}
+		}
 	}
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
 }
-
 #endif /* CONFIG_PM */
 
 #define INTEL8X0_TESTBUF_SIZE	32768	/* enough large for one shot */
@@ -2305,7 +2307,7 @@
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	/* check the position */
 	pos = ichdev->fragsize1;
-	pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift;
+	pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << ichdev->pos_shift;
 	pos += ichdev->position;
 	do_gettimeofday(&stop_time);
 	/* stop */
@@ -2546,9 +2548,9 @@
 		}
 		if (device_type == DEVICE_ALI)
 			ichdev->ali_slot = (ichdev->reg_offset - 0x40) / 0x10;
+		/* SIS7012 handles the pcm data in bytes, others are in samples */
+		ichdev->pos_shift = (device_type == DEVICE_SIS) ? 0 : 1;
 	}
-	/* SIS7012 handles the pcm data in bytes, others are in words */
-	chip->pcm_pos_shift = (device_type == DEVICE_SIS) ? 0 : 1;
 
 	memset(&chip->dma_dev, 0, sizeof(chip->dma_dev));
 	chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
@@ -2581,10 +2583,7 @@
 		return err;
 	}
 
-#ifdef CONFIG_PM
-	card->set_power_state = snd_intel8x0_set_power_state;
-	card->power_state_private_data = chip;
-#endif
+	snd_card_set_pm_callback(card, intel8x0_suspend, intel8x0_resume, chip);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_intel8x0_free(chip);
@@ -2692,16 +2691,14 @@
 		snd_card_free(card);
 		return err;
 	}
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_intel8x0_remove(struct pci_dev *pci)
 {
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -2710,10 +2707,7 @@
 	.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,
-#endif
+	SND_PCI_PM_CALLBACKS
 };
 
 
@@ -2817,12 +2811,9 @@
 {
 	int err;
 
-        if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Intel ICH soundcard not found or device busy\n");
-#endif
+        if ((err = pci_module_init(&driver)) < 0)
                 return err;
-        }
+
 #if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI)
 	if (pci_module_init(&joystick_driver) < 0) {
 		snd_printdd(KERN_INFO "no joystick found\n");
@@ -2847,33 +2838,3 @@
 
 module_init(alsa_card_intel8x0_init)
 module_exit(alsa_card_intel8x0_exit)
-
-#ifndef MODULE
-
-/* format is: snd-intel8x0=enable,index,id,ac97_clock,ac97_quirk,mpu_port,joystick */
-
-static int __init alsa_card_intel8x0_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 &&
-	       get_option(&str,&ac97_clock[nr_dev]) == 2 &&
-	       get_option(&str,&ac97_quirk[nr_dev]) == 2
-#ifdef SUPPORT_MIDI
-	       && get_option(&str,&mpu_port[nr_dev]) == 2
-#endif
-#ifdef SUPPORT_JOYSTICK
-	       && get_option(&str,&joystick[nr_dev]) == 2
-#endif
-	       );
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-intel8x0=", alsa_card_intel8x0_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/intel8x0m.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/intel8x0m.c	2004-05-27 18:34:20.000000000 +0100
@@ -31,12 +31,12 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -56,17 +56,18 @@
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel i8x0 modemcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Intel i8x0 modemcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ac97_clock, int, boot_devs, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
 MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0");
 
@@ -266,10 +267,6 @@
 	u32 int_sta_reg;		/* interrupt status register */
 	u32 int_sta_mask;		/* interrupt status mask */
 	unsigned int pcm_pos_shift;
-	
-#ifdef CONFIG_PM
-	int in_suspend;
-#endif
 };
 
 static struct pci_device_id snd_intel8x0m_ids[] = {
@@ -905,6 +902,7 @@
 	memset(&ac97, 0, sizeof(ac97));
 	ac97.private_data = chip;
 	ac97.private_free = snd_intel8x0_mixer_free_ac97;
+	ac97.scaps = AC97_SCAP_SKIP_AUDIO;
 
 	glob_sta = igetdword(chip, ICHREG(GLOB_STA));
 	bus.write = snd_intel8x0_codec_write;
@@ -1081,72 +1079,31 @@
 /*
  * power management
  */
-static void intel8x0_suspend(intel8x0_t *chip)
+static int intel8x0m_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->pm_private_data, return -EINVAL);
 	int i;
 
-	if (chip->in_suspend ||
-	    card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
-
-	chip->in_suspend = 1;
 	for (i = 0; i < chip->pcm_devs; i++)
 		snd_pcm_suspend_all(chip->pcm[i]);
+	if (chip->ac97)
+		snd_ac97_suspend(chip->ac97);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void intel8x0_resume(intel8x0_t *chip)
+static int intel8x0m_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
-
-	if (! chip->in_suspend ||
-	    card->power_state == SNDRV_CTL_POWER_D0)
-		return;
-
+	intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->pm_private_data, return -EINVAL);
 	pci_enable_device(chip->pci);
 	pci_set_master(chip->pci);
 	snd_intel8x0_chip_init(chip, 0);
 	if (chip->ac97)
 		snd_ac97_resume(chip->ac97);
 
-	chip->in_suspend = 0;
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_intel8x0m_suspend(struct pci_dev *dev, u32 state)
-{
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO);
-	intel8x0_suspend(chip);
-	return 0;
-}
-static int snd_intel8x0m_resume(struct pci_dev *dev)
-{
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO);
-	intel8x0_resume(chip);
 	return 0;
 }
-
-/* callback */
-static int snd_intel8x0_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->power_state_private_data, return -ENXIO);
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		intel8x0_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		intel8x0_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
 #endif /* CONFIG_PM */
 
 static void snd_intel8x0m_proc_read(snd_info_entry_t * entry,
@@ -1338,10 +1295,7 @@
 		return err;
 	}
 
-#ifdef CONFIG_PM
-	card->set_power_state = snd_intel8x0_set_power_state;
-	card->power_state_private_data = chip;
-#endif
+	snd_card_set_pm_callback(card, intel8x0m_suspend, intel8x0m_resume, chip);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_intel8x0_free(chip);
@@ -1436,16 +1390,14 @@
 		snd_card_free(card);
 		return err;
 	}
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_intel8x0m_remove(struct pci_dev *pci)
 {
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -1454,25 +1406,13 @@
 	.id_table = snd_intel8x0m_ids,
 	.probe = snd_intel8x0m_probe,
 	.remove = __devexit_p(snd_intel8x0m_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_intel8x0m_suspend,
-	.resume = snd_intel8x0m_resume,
-#endif
+	SND_PCI_PM_CALLBACKS
 };
 
 
 static int __init alsa_card_intel8x0m_init(void)
 {
-	int err;
-
-        if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Intel ICH modemcard not found or device busy\n");
-#endif
-                return err;
-        }
-
-        return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_intel8x0m_exit(void)
@@ -1482,26 +1422,3 @@
 
 module_init(alsa_card_intel8x0m_init)
 module_exit(alsa_card_intel8x0m_exit)
-
-#ifndef MODULE
-
-/* format is: snd-intel8x0=enable,index,id,ac97_clock,mpu_port,joystick */
-
-static int __init alsa_card_intel8x0m_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 &&
-	       get_option(&str,&ac97_clock[nr_dev]) == 2
-	       );
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-intel8x0m=", alsa_card_intel8x0m_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/korg1212/korg1212.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/korg1212/korg1212.c	2004-05-27 18:34:20.000000000 +0100
@@ -26,13 +26,13 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/io.h>
@@ -417,14 +417,15 @@
 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; /* Enable this card */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Korg 1212 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Korg 1212 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 MODULE_AUTHOR("Haroldo Gamal <gamal@alternex.com.br>");
@@ -2504,15 +2505,14 @@
 		snd_card_free(card);
 		return err;
 	}
-	pci_set_drvdata(pci, korg1212);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_korg1212_remove(struct pci_dev *pci)
 {
-	korg1212_t *korg1212 = pci_get_drvdata(pci);
-	snd_card_free(korg1212->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -2525,15 +2525,7 @@
 
 static int __init alsa_card_korg1212_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "No Korg 1212IO cards found\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_korg1212_exit(void)
@@ -2543,25 +2535,3 @@
 
 module_init(alsa_card_korg1212_init)
 module_exit(alsa_card_korg1212_exit)
-
-#ifndef MODULE
-
-/* format is: snd-korg1212=enable,index,id */
-
-static int __init alsa_card_korg1212_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-korg1212=", alsa_card_korg1212_setup);
-
-#endif /* ifndef MODULE */
-
--- diff/sound/pci/maestro3.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/maestro3.c	2004-05-27 18:34:20.000000000 +0100
@@ -39,13 +39,13 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/mpu401.h>
 #include <sound/ac97_codec.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>");
@@ -63,20 +63,21 @@
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* all enabled */
 static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 static int amp_gpio[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable this soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(external_amp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(external_amp, bool, boot_devs, 0444);
 MODULE_PARM_DESC(external_amp, "Enable external amp for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(external_amp, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
-MODULE_PARM(amp_gpio, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(amp_gpio, int, boot_devs, 0444);
 MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)");
 MODULE_PARM_SYNTAX(amp_gpio, SNDRV_ENABLED);
 
@@ -2410,18 +2411,16 @@
  * APM support
  */
 #ifdef CONFIG_PM
-
-static void m3_suspend(m3_t *chip)
+static int m3_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	m3_t *chip = snd_magic_cast(m3_t, card->pm_private_data, return -EINVAL);
 	int i, index;
 
 	if (chip->suspend_mem == NULL)
-		return;
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
+		return 0;
 
 	snd_pcm_suspend_all(chip->pcm);
+	snd_ac97_suspend(chip->ac97);
 
 	big_mdelay(10); /* give the assp a chance to idle.. */
 
@@ -2440,17 +2439,16 @@
 	snd_m3_outw(chip, 0xffff, 0x54);
 	snd_m3_outw(chip, 0xffff, 0x56);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void m3_resume(m3_t *chip)
+static int m3_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	m3_t *chip = snd_magic_cast(m3_t, card->pm_private_data, return -EINVAL);
 	int i, index;
 
 	if (chip->suspend_mem == NULL)
-		return;
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
+		return 0;
 
 	/* first lets just bring everything back. .*/
 	snd_m3_outw(chip, 0, 0x54);
@@ -2481,41 +2479,8 @@
 	snd_m3_amp_enable(chip, 1);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_m3_suspend(struct pci_dev *pci, u32 state)
-{
-	m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return -ENXIO);
-	m3_suspend(chip);
-	return 0;
-}
-static int snd_m3_resume(struct pci_dev *pci)
-{
-	m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return -ENXIO);
-	m3_resume(chip);
-	return 0;
-}
-
-/* callback */
-static int snd_m3_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	m3_t *chip = snd_magic_cast(m3_t, card->power_state_private_data, return -ENXIO);
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		m3_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		m3_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
-
 #endif /* CONFIG_PM */
 
 
@@ -2651,11 +2616,9 @@
 #ifdef CONFIG_PM
 	chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
 	if (chip->suspend_mem == NULL)
-		snd_printk("can't allocate apm buffer\n");
-	else {
-		card->set_power_state = snd_m3_set_power_state;
-		card->power_state_private_data = chip;
-	}
+		snd_printk(KERN_WARNING "can't allocate apm buffer\n");
+	else
+		snd_card_set_pm_callback(card, m3_suspend, m3_resume, chip);
 #endif
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
@@ -2738,16 +2701,14 @@
 		printk(KERN_WARNING "maestro3: no midi support.\n");
 #endif
 
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_m3_remove(struct pci_dev *pci)
 {
-	m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -2756,23 +2717,12 @@
 	.id_table = snd_m3_ids,
 	.probe = snd_m3_probe,
 	.remove = __devexit_p(snd_m3_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_m3_suspend,
-	.resume = snd_m3_resume,
-#endif
+	SND_PCI_PM_CALLBACKS
 };
 	
 static int __init alsa_card_m3_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Maestro3/Allegro soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_m3_exit(void)
@@ -2782,26 +2732,3 @@
 
 module_init(alsa_card_m3_init)
 module_exit(alsa_card_m3_exit)
-
-#ifndef MODULE
-
-/* format is: snd-maestro3=enable,index,id,external_amp,amp_gpio */
-
-static int __init alsa_card_maestro3_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 &&
-	       get_option(&str,&external_amp[nr_dev]) == 2 &&
-	       get_option(&str,&amp_gpio[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-maestro3=", alsa_card_maestro3_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/mixart/mixart.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/mixart/mixart.c	2004-05-27 18:34:20.000000000 +0100
@@ -25,8 +25,8 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -48,16 +48,17 @@
 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 */
+static int boot_devs;
 
 #define chip_t mixart_t
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 
@@ -1432,15 +1433,7 @@
 
 static int __init alsa_card_mixart_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		snd_printk(KERN_ERR "Digigram miXart soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_mixart_exit(void)
@@ -1450,24 +1443,3 @@
 
 module_init(alsa_card_mixart_init)
 module_exit(alsa_card_mixart_exit)
-
-#ifndef MODULE
-
-/* format is: snd-mixart=enable,index,id */
-
-static int __init alsa_card_mixart_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-mixart=", alsa_card_mixart_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/nm256/nm256.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/nm256/nm256.c	2004-05-27 18:34:20.000000000 +0100
@@ -31,12 +31,12 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #define CARD_NAME "NeoMagic 256AV/ZX"
@@ -62,32 +62,33 @@
 static int buffer_top[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* not specified */
 static int use_cache[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* disabled */
 static int vaio_hack[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* disabled */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable this soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(playback_bufsize, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(playback_bufsize, int, boot_devs, 0444);
 MODULE_PARM_DESC(playback_bufsize, "DAC frame size in kB for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(playback_bufsize, SNDRV_ENABLED);
-MODULE_PARM(capture_bufsize, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(capture_bufsize, int, boot_devs, 0444);
 MODULE_PARM_DESC(capture_bufsize, "ADC frame size in kB for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(capture_bufsize, SNDRV_ENABLED);
-MODULE_PARM(force_ac97, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(force_ac97, bool, boot_devs, 0444);
 MODULE_PARM_DESC(force_ac97, "Force to use AC97 codec for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(force_ac97, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
-MODULE_PARM(buffer_top, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(buffer_top, int, boot_devs, 0444);
 MODULE_PARM_DESC(buffer_top, "Set the top address of audio buffer for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(buffer_top, SNDRV_ENABLED);
-MODULE_PARM(use_cache, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(use_cache, bool, boot_devs, 0444);
 MODULE_PARM_DESC(use_cache, "Enable the cache for coefficient table access.");
 MODULE_PARM_SYNTAX(use_cache, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
-MODULE_PARM(vaio_hack, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(vaio_hack, bool, boot_devs, 0444);
 MODULE_PARM_DESC(vaio_hack, "Enable workaround for Sony VAIO notebooks.");
 MODULE_PARM_SYNTAX(vaio_hack, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 
@@ -274,11 +275,15 @@
 #ifndef PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO
 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
 #endif
+#ifndef PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO
+#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016
+#endif
 
 
 static struct pci_device_id snd_nm256_ids[] = {
 	{PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0,},
 };
 
@@ -1283,24 +1288,20 @@
  * APM event handler, so the card is properly reinitialized after a power
  * event.
  */
-static void nm256_suspend(nm256_t *chip)
+static int nm256_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
+	nm256_t *chip = snd_magic_cast(nm256_t, card->pm_private_data, return -EINVAL);
 
 	snd_pcm_suspend_all(chip->pcm);
+	snd_ac97_suspend(chip->ac97);
 	chip->coeffs_current = 0;
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void nm256_resume(nm256_t *chip)
+static int nm256_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
+	nm256_t *chip = snd_magic_cast(nm256_t, card->pm_private_data, return -EINVAL);
 
 	/* Perform a full reset on the hardware */
 	pci_enable_device(chip->pci);
@@ -1310,41 +1311,8 @@
 	snd_ac97_resume(chip->ac97);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_nm256_suspend(struct pci_dev *dev, u32 state)
-{
-	nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return -ENXIO);
-	nm256_suspend(chip);
-	return 0;
-}
-static int snd_nm256_resume(struct pci_dev *dev)
-{
-	nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return -ENXIO);
-	nm256_resume(chip);
-	return 0;
-}
-
-/* callback */
-static int snd_nm256_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	nm256_t *chip = snd_magic_cast(nm256_t, card->power_state_private_data, return -ENXIO);
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		nm256_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		nm256_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
-
 #endif /* CONFIG_PM */
 
 static int snd_nm256_free(nm256_t *chip)
@@ -1552,10 +1520,7 @@
 
 	// pci_set_master(pci); /* needed? */
 	
-#ifdef CONFIG_PM
-	card->set_power_state = snd_nm256_set_power_state;
-	card->power_state_private_data = chip;
-#endif
+	snd_card_set_pm_callback(card, nm256_suspend, nm256_resume, chip);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
 		goto __error;
@@ -1571,6 +1536,21 @@
 }
 
 
+struct nm256_quirk {
+	unsigned short vendor;
+	unsigned short device;
+	int type;
+};
+
+#define NM_BLACKLISTED	1
+
+static struct nm256_quirk nm256_quirks[] __devinitdata = {
+	/* HP omnibook 4150 has cs4232 codec internally */
+	{ .vendor = 0x103c, .device = 0x0007, .type = NM_BLACKLISTED },
+	{ } /* terminator */
+};
+
+
 static int __devinit snd_nm256_probe(struct pci_dev *pci,
 				     const struct pci_device_id *pci_id)
 {
@@ -1579,6 +1559,8 @@
 	nm256_t *chip;
 	int err;
 	unsigned int xbuffer_top;
+	struct nm256_quirk *q;
+	u16 subsystem_vendor, subsystem_device;
 
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
@@ -1590,6 +1572,18 @@
 		return -ENOENT;
 	}
 
+	pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
+	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
+
+	for (q = nm256_quirks; q->vendor; q++) {
+		if (q->vendor == subsystem_vendor && q->device == subsystem_device) {
+			if (q->type == NM_BLACKLISTED) {
+				printk(KERN_INFO "nm256: The device is blacklisted.  Loading stopped\n");
+				return -ENODEV;
+			}
+		}
+	}
+
 	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
 	if (card == NULL)
 		return -ENOMEM;
@@ -1601,6 +1595,9 @@
 	case PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO:
 		strcpy(card->driver, "NM256ZX");
 		break;
+	case PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO:
+		strcpy(card->driver, "NM256XL+");
+		break;
 	default:
 		snd_printk("invalid device id 0x%x\n", pci->device);
 		snd_card_free(card);
@@ -1641,16 +1638,14 @@
 		return err;
 	}
 
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_nm256_remove(struct pci_dev *pci)
 {
-	nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -1660,23 +1655,13 @@
 	.id_table = snd_nm256_ids,
 	.probe = snd_nm256_probe,
 	.remove = __devexit_p(snd_nm256_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_nm256_suspend,
-	.resume = snd_nm256_resume,
-#endif
+	SND_PCI_PM_CALLBACKS
 };
 
 
 static int __init alsa_card_nm256_init(void)
 {
-	int err;
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "NeoMagic 256 audio soundchip not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_nm256_exit(void)
@@ -1686,31 +1671,3 @@
 
 module_init(alsa_card_nm256_init)
 module_exit(alsa_card_nm256_exit)
-
-#ifndef MODULE
-
-/* format is: snd-nm256=enable,index,id,
-			playback_bufsize,capture_bufsize,
-			force_ac97,buffer_top,use_cache */
-
-static int __init alsa_card_nm256_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 &&
-	       get_option(&str,&playback_bufsize[nr_dev]) == 2 &&
-	       get_option(&str,&capture_bufsize[nr_dev]) == 2 &&
-	       get_option(&str,&force_ac97[nr_dev]) == 2 &&
-	       get_option(&str,&buffer_top[nr_dev]) == 2 &&
-	       get_option(&str,&use_cache[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-nm256=", alsa_card_nm256_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/rme32.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/rme32.c	2004-05-27 18:34:20.000000000 +0100
@@ -61,6 +61,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -68,7 +69,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/io.h>
@@ -76,14 +76,15 @@
 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 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Digi32 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for RME Digi32 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable RME Digi32 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>");
@@ -1995,15 +1996,7 @@
 
 static int __init alsa_card_rme32_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		snd_printk("No RME Digi32 cards found\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_rme32_exit(void)
@@ -2013,22 +2006,3 @@
 
 module_init(alsa_card_rme32_init)
 module_exit(alsa_card_rme32_exit)
-
-#ifndef MODULE
-
-static int __init alsa_card_rme32_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-rme32=", alsa_card_rme32_setup);
-
-#endif				/* ifndef MODULE */
--- diff/sound/pci/rme96.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/rme96.c	2004-05-27 18:34:20.000000000 +0100
@@ -29,6 +29,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -36,7 +37,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/io.h>
@@ -57,14 +57,15 @@
 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 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Digi96 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for RME Digi96 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 
@@ -2565,15 +2566,7 @@
 
 static int __init alsa_card_rme96_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "No RME Digi96 cards found\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_rme96_exit(void)
@@ -2583,24 +2576,3 @@
 
 module_init(alsa_card_rme96_init)
 module_exit(alsa_card_rme96_exit)
-
-#ifndef MODULE
-
-/* format is: snd-rme96=enable,index,id */
-
-static int __init alsa_card_rme96_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-rme96=", alsa_card_rme96_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/rme9652/hdsp.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/rme9652/hdsp.c	2004-05-27 18:34:20.000000000 +0100
@@ -27,6 +27,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/moduleparam.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -35,7 +36,6 @@
 #include <sound/asoundef.h>
 #include <sound/rawmidi.h>
 #include <sound/hwdep.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/hdsp.h>
 
@@ -48,20 +48,21 @@
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int precise_ptr[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Enable precise pointer */
 static int line_outs_monitor[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0}; /* Send all inputs/playback to line outs */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Hammerfall DSP interface.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for RME Hammerfall DSP interface.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable/disable specific Hammerfall DSP soundcards.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(precise_ptr, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(precise_ptr, bool, boot_devs, 0444);
 MODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably).");
 MODULE_PARM_SYNTAX(precise_ptr, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
-MODULE_PARM(line_outs_monitor,"1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(line_outs_monitor, bool, boot_devs, 0444);
 MODULE_PARM_DESC(line_outs_monitor, "Send all input and playback streams to line outs by default.");
 MODULE_PARM_SYNTAX(line_outs_monitor, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 MODULE_AUTHOR("Paul Davis <paul@linuxaudiosystems.com>, Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
@@ -634,6 +635,7 @@
 	case 0xa:
 		return (64 * out) + (32 + (in));
 	case 0x96:
+	case 0x97:
 		return (32 * out) + (16 + (in));
 	default:
 		return (52 * out) + (26 + (in));
@@ -646,6 +648,7 @@
 	case 0xa:
 		return (64 * out) + in;
 	case 0x96:
+	case 0x97:
 		return (32 * out) + in;
 	default:
 		return (52 * out) + in;
@@ -4120,10 +4123,10 @@
 		return -EIO;
 	}
 
-	spin_lock_irq(&hdsp->lock);
+	spin_lock(&hdsp->lock);
 	if (!hdsp->running)
 		hdsp_reset_hw_pointer(hdsp);
-	spin_unlock_irq(&hdsp->lock);
+	spin_unlock(&hdsp->lock);
 	return result;
 }
 
@@ -5018,6 +5021,7 @@
 		is_9652 = 1;
 		break;
 	case 0x96:
+	case 0x97:
 		hdsp->card_name = "RME HDSP 9632";
 		hdsp->max_channels = 16;
 		is_9632 = 1;
@@ -5198,14 +5202,7 @@
 
 static int __init alsa_card_hdsp_init(void)
 {
-	if (pci_module_init(&driver) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "RME Hammerfall-DSP: no cards found\n");
-#endif
-		return -ENODEV;
-	}
-
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_hdsp_exit(void)
@@ -5215,24 +5212,3 @@
 
 module_init(alsa_card_hdsp_init)
 module_exit(alsa_card_hdsp_exit)
-
-#ifndef MODULE
-
-/* format is: snd-hdsp=enable,index,id */
-
-static int __init alsa_card_hdsp_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-hdsp=", alsa_card_hdsp_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/rme9652/rme9652.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/rme9652/rme9652.c	2004-05-27 18:34:20.000000000 +0100
@@ -26,13 +26,13 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
 #include <sound/asoundef.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/current.h>
@@ -42,17 +42,18 @@
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int precise_ptr[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Enable precise pointer */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for RME Digi9652 (Hammerfall) soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable/disable specific RME96{52,36} soundcards.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(precise_ptr, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(precise_ptr, bool, boot_devs, 0444);
 MODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably).");
 MODULE_PARM_SYNTAX(precise_ptr, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 MODULE_AUTHOR("Paul Davis <pbd@op.net>, Winfried Ritsch");
@@ -2262,10 +2263,10 @@
 	rme9652_t *rme9652 = _snd_pcm_substream_chip(substream);
 	int result = 0;
 
-	spin_lock_irq(&rme9652->lock);
+	spin_lock(&rme9652->lock);
 	if (!rme9652->running)
 		rme9652_reset_hw_pointer(rme9652);
-	spin_unlock_irq(&rme9652->lock);
+	spin_unlock(&rme9652->lock);
 	return result;
 }
 
@@ -2748,14 +2749,7 @@
 
 static int __init alsa_card_hammerfall_init(void)
 {
-	if (pci_module_init(&driver) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "RME Digi9652/Digi9636: no cards found\n");
-#endif
-		return -ENODEV;
-	}
-
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_hammerfall_exit(void)
@@ -2765,24 +2759,3 @@
 
 module_init(alsa_card_hammerfall_init)
 module_exit(alsa_card_hammerfall_exit)
-
-#ifndef MODULE
-
-/* format is: snd-rme9652=enable,index,id */
-
-static int __init alsa_card_rme9652_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-rme9652=", alsa_card_rme9652_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/sonicvibes.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/sonicvibes.c	2004-05-27 18:34:20.000000000 +0100
@@ -29,6 +29,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -36,7 +37,6 @@
 #include <sound/control.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/io.h>
@@ -60,23 +60,24 @@
 static int reverb[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
 static int mge[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
 static unsigned int dmaio = 0x7a00;	/* DDMA i/o address */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for S3 SonicVibes soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for S3 SonicVibes soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable S3 SonicVibes soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(reverb, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(reverb, bool, boot_devs, 0444);
 MODULE_PARM_DESC(reverb, "Enable reverb (SRAM is present) for S3 SonicVibes soundcard.");
 MODULE_PARM_SYNTAX(reverb, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
-MODULE_PARM(mge, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mge, bool, boot_devs, 0444);
 MODULE_PARM_DESC(mge, "MIC Gain Enable for S3 SonicVibes soundcard.");
 MODULE_PARM_SYNTAX(mge, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
-MODULE_PARM(dmaio, "i");
+module_param(dmaio, uint, 0444);
 MODULE_PARM_DESC(dmaio, "DDMA i/o base address for S3 SonicVibes soundcard.");
 MODULE_PARM_SYNTAX(dmaio, "global," SNDRV_PORT_DESC);
 
@@ -1535,15 +1536,7 @@
 
 static int __init alsa_card_sonicvibes_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "S3 SonicVibes soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_sonicvibes_exit(void)
@@ -1553,28 +1546,3 @@
 
 module_init(alsa_card_sonicvibes_init)
 module_exit(alsa_card_sonicvibes_exit)
-
-#ifndef MODULE
-
-/* format is: snd-sonicvibes=enable,index,id,
-			     reverb,mge,dmaio */
-
-static int __init alsa_card_sonicvibes_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 &&
-	       get_option(&str,&reverb[nr_dev]) == 2 &&
-	       get_option(&str,&mge[nr_dev]) == 2 &&
-	       get_option(&str,(int *)&dmaio) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-sonicvibes=", alsa_card_sonicvibes_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/trident/trident.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/trident/trident.c	2004-05-27 18:34:20.000000000 +0100
@@ -25,9 +25,9 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/trident.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, <audio@tridentmicro.com>");
@@ -52,20 +52,21 @@
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 32};
 static int wavetable_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8192};
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Trident 4DWave PCI soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Trident 4DWave PCI soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Trident 4DWave PCI soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(pcm_channels, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pcm_channels, int, boot_devs, 0444);
 MODULE_PARM_DESC(pcm_channels, "Number of hardware channels assigned for PCM.");
 MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",default:32,allows:{{1,32}}");
-MODULE_PARM(wavetable_size, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(wavetable_size, int, boot_devs, 0444);
 MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth.");
 MODULE_PARM_SYNTAX(wavetable_size, SNDRV_ENABLED ",default:8192,skill:advanced");
 
@@ -169,56 +170,28 @@
 		snd_card_free(card);
 		return err;
 	}
-	pci_set_drvdata(pci, trident);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
 static void __devexit snd_trident_remove(struct pci_dev *pci)
 {
-	trident_t *trident = snd_magic_cast(trident_t, pci_get_drvdata(pci), return);
-	if (trident)
-		snd_card_free(trident->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
-static int snd_card_trident_suspend(struct pci_dev *pci, u32 state)
-{
-	trident_t *chip = snd_magic_cast(trident_t, pci_get_drvdata(pci), return -ENXIO);
-	snd_trident_suspend(chip);
-	return 0;
-}
-static int snd_card_trident_resume(struct pci_dev *pci)
-{
-	trident_t *chip = snd_magic_cast(trident_t, pci_get_drvdata(pci), return -ENXIO);
-	snd_trident_resume(chip);
-	return 0;
-}
-#endif
-
 static struct pci_driver driver = {
 	.name = "Trident4DWaveAudio",
 	.id_table = snd_trident_ids,
 	.probe = snd_trident_probe,
 	.remove = __devexit_p(snd_trident_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_card_trident_suspend,
-	.resume = snd_card_trident_resume,
-#endif
+	SND_PCI_PM_CALLBACKS
 };
 
 static int __init alsa_card_trident_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Trident 4DWave PCI soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_trident_exit(void)
@@ -228,27 +201,3 @@
 
 module_init(alsa_card_trident_init)
 module_exit(alsa_card_trident_exit)
-
-#ifndef MODULE
-
-/* format is: snd-trident=enable,index,id,
-			  pcm_channels,wavetable_size */
-
-static int __init alsa_card_trident_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 &&
-	       get_option(&str,&pcm_channels[nr_dev]) == 2 &&
-	       get_option(&str,&wavetable_size[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-trident=", alsa_card_trident_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/trident/trident_main.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/trident/trident_main.c	2004-05-27 18:34:20.000000000 +0100
@@ -50,7 +50,8 @@
 static int snd_trident_pcm_mixer_free(trident_t *trident, snd_trident_voice_t * voice, snd_pcm_substream_t *substream);
 static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 #ifdef CONFIG_PM
-static int snd_trident_set_power_state(snd_card_t *card, unsigned int power_state);
+static int snd_trident_suspend(snd_card_t *card, unsigned int state);
+static int snd_trident_resume(snd_card_t *card, unsigned int state);
 #endif
 static int snd_trident_sis_reset(trident_t *trident);
 
@@ -3646,10 +3647,8 @@
 
 	snd_trident_enable_eso(trident);
 
-#ifdef CONFIG_PM
-	card->set_power_state = snd_trident_set_power_state;
-	card->power_state_private_data = trident;
-#endif
+	
+	snd_card_set_pm_callback(card, snd_trident_suspend, snd_trident_resume, trident);
 
 	snd_trident_proc_init(trident);
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, trident, &ops)) < 0) {
@@ -3949,19 +3948,21 @@
 }
 
 #ifdef CONFIG_PM
-
-void snd_trident_suspend(trident_t *trident)
+static int snd_trident_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = trident->card;
+	trident_t *trident = snd_magic_cast(trident_t, card->pm_private_data, return -EINVAL);
 
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
 	trident->in_suspend = 1;
 	snd_pcm_suspend_all(trident->pcm);
 	if (trident->foldback)
 		snd_pcm_suspend_all(trident->foldback);
 	if (trident->spdif)
 		snd_pcm_suspend_all(trident->spdif);
+
+	snd_ac97_suspend(trident->ac97);
+	if (trident->ac97_sec)
+		snd_ac97_suspend(trident->ac97_sec);
+
 	switch (trident->device) {
 	case TRIDENT_DEVICE_ID_DX:
 	case TRIDENT_DEVICE_ID_NX:
@@ -3970,14 +3971,12 @@
 		break;
 	}
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-void snd_trident_resume(trident_t *trident)
+static int snd_trident_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = trident->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
+	trident_t *trident = snd_magic_cast(trident_t, card->pm_private_data, return -EINVAL);
 
 	pci_enable_device(trident->pci);
 	if (pci_set_dma_mask(trident->pci, 0x3fffffff) < 0 ||
@@ -3998,6 +3997,8 @@
 	}
 
 	snd_ac97_resume(trident->ac97);
+	if (trident->ac97_sec)
+		snd_ac97_resume(trident->ac97_sec);
 
 	/* restore some registers */
 	outl(trident->musicvol_wavevol, TRID_REG(trident, T4D_MUSICVOL_WAVEVOL));
@@ -4006,28 +4007,8 @@
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	trident->in_suspend = 0;
+	return 0;
 }
-
-static int snd_trident_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	trident_t *chip = snd_magic_cast(trident_t, card->power_state_private_data, return -ENXIO);
-        
-	switch (power_state) {
-        case SNDRV_CTL_POWER_D0:
-        case SNDRV_CTL_POWER_D1:
-        case SNDRV_CTL_POWER_D2:
-        	snd_trident_resume(chip);
-                break;
-	case SNDRV_CTL_POWER_D3hot:
-        case SNDRV_CTL_POWER_D3cold:
-		snd_trident_suspend(chip);
-		break;
-        default:
-	        return -EINVAL;
-        }
-        return 0;
-}
-
 #endif /* CONFIG_PM */
 
 EXPORT_SYMBOL(snd_trident_alloc_voice);
--- diff/sound/pci/via82xx.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/via82xx.c	2004-05-27 18:34:20.000000000 +0100
@@ -51,13 +51,13 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <sound/ac97_codec.h>
 #include <sound/mpu401.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #if 0
@@ -84,31 +84,32 @@
 static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
 static int ac97_quirk[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = AC97_TUNE_DEFAULT};
 static int dxs_support[SNDRV_CARDS];
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for VIA 82xx bridge.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable audio part of VIA 82xx bridge.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port. (VT82C686x only)");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT_DESC);
 #ifdef SUPPORT_JOYSTICK
-MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(joystick, bool, boot_devs, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)");
 MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLE_DESC "," SNDRV_BOOLEAN_FALSE_DESC);
 #endif
-MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ac97_clock, int, boot_devs, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
 MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000");
-MODULE_PARM(ac97_quirk, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ac97_quirk, int, boot_devs, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,4}},dialog:list,default:-1");
-MODULE_PARM(dxs_support, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(dxs_support, int, boot_devs, 0444);
 MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)");
 MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,4}},dialog:list");
 
@@ -368,6 +369,14 @@
 
 	unsigned char old_legacy;
 	unsigned char old_legacy_cfg;
+#ifdef CONFIG_PM
+	unsigned char legacy_saved;
+	unsigned char legacy_cfg_saved;
+	unsigned char spdif_ctrl_saved;
+	unsigned char capture_src_saved[2];
+	unsigned int mpu_port_saved;
+	u32 pci_state[16];
+#endif
 
 	unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */
 
@@ -384,6 +393,7 @@
 	unsigned int no_vra: 1;		/* no need to set VRA on DXS channels */
 	unsigned int spdif_on: 1;	/* only spdif rates work to external DACs */
 
+	snd_pcm_t *pcms[2];
 	snd_rawmidi_t *rmidi;
 
 	ac97_bus_t *ac97_bus;
@@ -1289,6 +1299,7 @@
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
 	pcm->private_data = chip;
 	strcpy(pcm->name, chip->card->shortname);
+	chip->pcms[0] = pcm;
 	/* set up playbacks */
 	for (i = 0; i < 4; i++)
 		init_viadev(chip, i, 0x10 * i, 0);
@@ -1307,6 +1318,7 @@
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
 	pcm->private_data = chip;
 	strcpy(pcm->name, chip->card->shortname);
+	chip->pcms[1] = pcm;
 	/* set up playback */
 	init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 0);
 	/* set up capture */
@@ -1341,6 +1353,7 @@
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
 	pcm->private_data = chip;
 	strcpy(pcm->name, chip->card->shortname);
+	chip->pcms[0] = pcm;
 	/* set up playback */
 	init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 0);
 	/* capture */
@@ -1357,6 +1370,7 @@
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops);
 	pcm->private_data = chip;
 	strcpy(pcm->name, chip->card->shortname);
+	chip->pcms[1] = pcm;
 	/* set up playback */
 	init_viadev(chip, chip->playback_devno, 0x30, 0);
 
@@ -1387,6 +1401,7 @@
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops);
 	pcm->private_data = chip;
 	strcpy(pcm->name, chip->card->shortname);
+	chip->pcms[0] = pcm;
 	init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0);
 	init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 1);
 
@@ -1404,8 +1419,11 @@
 
 static int snd_via8233_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
+	/* formerly they were "Line" and "Mic", but it looks like that they
+	 * have nothing to do with the actual physical connections...
+	 */
 	static char *texts[2] = {
-		"Line", "Mic"
+		"Input1", "Input2"
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
@@ -1584,6 +1602,12 @@
 		.name = "Mitac Mobo",
 		.type = AC97_TUNE_ALC_JACK
 	},
+	{
+		.vendor = 0x161f,
+		.device = 0x202b,
+		.name = "Arima Notebook",
+		.type = AC97_TUNE_HP_ONLY,
+	},
 	{ } /* terminator */
 };
 
@@ -1667,6 +1691,9 @@
 		if (mpu_port[dev] >= 0x200) {	/* force MIDI */
 			mpu_port[dev] &= 0xfffc;
 			pci_write_config_dword(chip->pci, 0x18, mpu_port[dev] | 0x01);
+#ifdef CONFIG_PM
+			chip->mpu_port_saved = mpu_port[dev];
+#endif
 		} else {
 			mpu_port[dev] = pci_resource_start(chip->pci, 2);
 		}
@@ -1725,6 +1752,11 @@
 		gameport_register_port(&chip->gameport);
 #endif
 
+#ifdef CONFIG_PM
+	chip->legacy_saved = legacy;
+	chip->legacy_cfg_saved = legacy_cfg;
+#endif
+
 	return 0;
 }
 
@@ -1865,6 +1897,74 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+/*
+ * power management
+ */
+static int snd_via82xx_suspend(snd_card_t *card, unsigned int state)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, card->pm_private_data, return -EINVAL);
+	int i;
+
+	for (i = 0; i < 2; i++)
+		if (chip->pcms[i])
+			snd_pcm_suspend_all(chip->pcms[i]);
+	for (i = 0; i < chip->num_devs; i++)
+		snd_via82xx_channel_reset(chip, &chip->devs[i]);
+	synchronize_irq(chip->irq);
+	snd_ac97_suspend(chip->ac97);
+
+	/* save misc values */
+	if (chip->chip_type != TYPE_VIA686) {
+		pci_read_config_byte(chip->pci, VIA8233_SPDIF_CTRL, &chip->spdif_ctrl_saved);
+		chip->capture_src_saved[0] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL);
+		chip->capture_src_saved[1] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10);
+	}
+
+	pci_save_state(chip->pci, chip->pci_state);
+	pci_set_power_state(chip->pci, 3);
+	pci_disable_device(chip->pci);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
+}
+
+static int snd_via82xx_resume(snd_card_t *card, unsigned int state)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, card->pm_private_data, return -EINVAL);
+	int idx, i;
+
+	pci_enable_device(chip->pci);
+	pci_restore_state(chip->pci, chip->pci_state);
+	pci_set_power_state(chip->pci, 0);
+
+	snd_via82xx_chip_init(chip);
+
+	if (chip->chip_type == TYPE_VIA686) {
+		if (chip->mpu_port_saved)
+			pci_write_config_dword(chip->pci, 0x18, chip->mpu_port_saved | 0x01);
+		pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->legacy_saved);
+		pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, chip->legacy_cfg_saved);
+	} else {
+		pci_write_config_byte(chip->pci, VIA8233_SPDIF_CTRL, chip->spdif_ctrl_saved);
+		outb(chip->capture_src_saved[0], chip->port + VIA_REG_CAPTURE_CHANNEL);
+		outb(chip->capture_src_saved[1], chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10);
+		for (idx = 0; idx < 4; idx++) {
+			unsigned long port = chip->port + 0x10 * idx;
+			for (i = 0; i < 2; i++)
+				outb(chip->playback_volume[idx][i], port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i);
+		}
+	}
+
+	snd_ac97_resume(chip->ac97);
+
+	for (i = 0; i < chip->num_devs; i++)
+		snd_via82xx_channel_reset(chip, &chip->devs[i]);
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
 static int snd_via82xx_free(via82xx_t *chip)
 {
 	unsigned int i;
@@ -2010,7 +2110,8 @@
 	static struct dxs_whitelist whitelist[] = {
 		{ .vendor = 0x1005, .device = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */
 		{ .vendor = 0x1019, .device = 0x0996, .action = VIA_DXS_48K },
-		{ .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_ENABLE }, /* ASUS A7V8X */
+		{ .vendor = 0x1019, .device = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
+		{ .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
 		{ .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
 		{ .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ 
 		{ .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
@@ -2025,6 +2126,8 @@
 		{ .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
 		{ .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
 		{ .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
+		{ .vendor = 0x161f, .device = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
+		{ .vendor = 0x161f, .device = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */
 		{ .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
 		{ .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
 		{ .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
@@ -2145,6 +2248,9 @@
 		if ((err = snd_via8233_init_misc(chip, dev)) < 0)
 			goto __error;
 	}
+
+	snd_card_set_pm_callback(card, snd_via82xx_suspend, snd_via82xx_resume, chip);
+
 	/* disable interrupts */
 	for (i = 0; i < chip->num_devs; i++)
 		snd_via82xx_channel_reset(chip, &chip->devs[i]);
@@ -2178,19 +2284,12 @@
 	.id_table = snd_via82xx_ids,
 	.probe = snd_via82xx_probe,
 	.remove = __devexit_p(snd_via82xx_remove),
+	SND_PCI_PM_CALLBACKS
 };
 
 static int __init alsa_card_via82xx_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "VIA 82xx soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_via82xx_exit(void)
@@ -2200,33 +2299,3 @@
 
 module_init(alsa_card_via82xx_init)
 module_exit(alsa_card_via82xx_exit)
-
-#ifndef MODULE
-
-/* format is: snd-via82xx=enable,index,id,
-			  mpu_port,joystick,
-			  ac97_quirk,ac97_clock,dxs_support */
-
-static int __init alsa_card_via82xx_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 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2 &&
-#ifdef SUPPORT_JOYSTICK
-	       get_option(&str,&joystick[nr_dev]) == 2 &&
-#endif
-	       get_option(&str,&ac97_quirk[nr_dev]) == 2 &&
-	       get_option(&str,&ac97_clock[nr_dev]) == 2 &&
-	       get_option(&str,&dxs_support[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-via82xx=", alsa_card_via82xx_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/vx222/vx222.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/vx222/vx222.c	2004-05-27 18:34:20.000000000 +0100
@@ -23,8 +23,8 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include "vx222.h"
 
@@ -43,20 +43,21 @@
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int mic[SNDRV_CARDS]; /* microphone */
 static int ibl[SNDRV_CARDS]; /* microphone */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(mic, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(mic, bool, boot_devs, 0444);
 MODULE_PARM_DESC(mic, "Enable Microphone.");
 MODULE_PARM_SYNTAX(mic, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
-MODULE_PARM(ibl, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ibl, int, boot_devs, 0444);
 MODULE_PARM_DESC(ibl, "Capture IBL size.");
 MODULE_PARM_SYNTAX(ibl, SNDRV_ENABLED);
 
@@ -272,15 +273,7 @@
 
 static int __init alsa_card_vx222_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Digigram VX222 soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_vx222_exit(void)
@@ -290,24 +283,3 @@
 
 module_init(alsa_card_vx222_init)
 module_exit(alsa_card_vx222_exit)
-
-#ifndef MODULE
-
-/* format is: snd-vx222=enable,index,id */
-
-static int __init alsa_card_vx222_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-vx222=", alsa_card_vx222_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/ymfpci/ymfpci.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ymfpci/ymfpci.c	2004-05-27 18:34:20.000000000 +0100
@@ -23,11 +23,11 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/ymfpci.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -50,28 +50,29 @@
 static long joystick_port[SNDRV_CARDS];
 #endif
 static int rear_switch[SNDRV_CARDS];
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for the Yamaha DS-XG PCI soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for the Yamaha DS-XG PCI soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Yamaha DS-XG soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(mpu_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 Port.");
 MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED);
-MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(fm_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(fm_port, "FM OPL-3 Port.");
 MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED);
 #ifdef SUPPORT_JOYSTICK
-MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+module_param_array(joystick_port, long, boot_devs, 0444);
 MODULE_PARM_DESC(joystick_port, "Joystick port address");
 MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED);
 #endif
-MODULE_PARM(rear_switch, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(rear_switch, bool, boot_devs, 0444);
 MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
 MODULE_PARM_SYNTAX(rear_switch, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 
@@ -311,31 +312,14 @@
 		snd_card_free(card);
 		return err;
 	}
-	pci_set_drvdata(pci, chip);
+	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int snd_card_ymfpci_suspend(struct pci_dev *pci, u32 state)
-{
-	ymfpci_t *chip = snd_magic_cast(ymfpci_t, pci_get_drvdata(pci), return -ENXIO);
-	snd_ymfpci_suspend(chip);
-	return 0;
-}
-static int snd_card_ymfpci_resume(struct pci_dev *pci)
-{
-	ymfpci_t *chip = snd_magic_cast(ymfpci_t, pci_get_drvdata(pci), return -ENXIO);
-	snd_ymfpci_resume(chip);
-	return 0;
-}
-#endif
-
 static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci)
 {
-	ymfpci_t *chip = snd_magic_cast(ymfpci_t, pci_get_drvdata(pci), return);
-	if (chip)
-		snd_card_free(chip->card);
+	snd_card_free(pci_get_drvdata(pci));
 	pci_set_drvdata(pci, NULL);
 }
 
@@ -344,23 +328,12 @@
 	.id_table = snd_ymfpci_ids,
 	.probe = snd_card_ymfpci_probe,
 	.remove = __devexit_p(snd_card_ymfpci_remove),
-#ifdef CONFIG_PM
-	.suspend = snd_card_ymfpci_suspend,
-	.resume = snd_card_ymfpci_resume,
-#endif	
+	SND_PCI_PM_CALLBACKS
 };
 
 static int __init alsa_card_ymfpci_init(void)
 {
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "Yamaha DS-XG PCI soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
+	return pci_module_init(&driver);
 }
 
 static void __exit alsa_card_ymfpci_exit(void)
@@ -370,27 +343,3 @@
 
 module_init(alsa_card_ymfpci_init)
 module_exit(alsa_card_ymfpci_exit)
-
-#ifndef MODULE
-
-/* format is: snd-ymfpci=enable,index,id,
-			 fm_port,mpu_port */
-
-static int __init alsa_card_ymfpci_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 &&
-	       get_option_long(&str,&fm_port[nr_dev]) == 2 &&
-	       get_option_long(&str,&mpu_port[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-ymfpci=", alsa_card_ymfpci_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/pci/ymfpci/ymfpci_main.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ymfpci/ymfpci_main.c	2004-05-27 18:34:20.000000000 +0100
@@ -2157,33 +2157,30 @@
 };
 #define YDSXGR_NUM_SAVED_REGS	ARRAY_SIZE(saved_regs_index)
 
-void snd_ymfpci_suspend(ymfpci_t *chip)
+static int snd_ymfpci_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	ymfpci_t *chip = snd_magic_cast(ymfpci_t, card->pm_private_data, return -EINVAL);
 	unsigned int i;
 	
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
 	snd_pcm_suspend_all(chip->pcm);
 	snd_pcm_suspend_all(chip->pcm2);
 	snd_pcm_suspend_all(chip->pcm_spdif);
 	snd_pcm_suspend_all(chip->pcm_4ch);
+	snd_ac97_suspend(chip->ac97);
 	for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++)
 		chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]);
 	chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE);
 	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
 	snd_ymfpci_disable_dsp(chip);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-void snd_ymfpci_resume(ymfpci_t *chip)
+static int snd_ymfpci_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	ymfpci_t *chip = snd_magic_cast(ymfpci_t, card->pm_private_data, return -EINVAL);
 	unsigned int i;
 
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
-
 	pci_enable_device(chip->pci);
 	pci_set_master(chip->pci);
 	snd_ymfpci_aclink_reset(chip->pci);
@@ -2205,25 +2202,6 @@
 		spin_unlock_irqrestore(&chip->reg_lock, flags);
 	}
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_ymfpci_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	ymfpci_t *chip = snd_magic_cast(ymfpci_t, card->power_state_private_data, return -ENXIO);
-
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		snd_ymfpci_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		snd_ymfpci_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
 #endif /* CONFIG_PM */
@@ -2304,8 +2282,7 @@
 		snd_ymfpci_free(chip);
 		return -ENOMEM;
 	}
-	card->set_power_state = snd_ymfpci_set_power_state;
-	card->power_state_private_data = chip;
+	snd_card_set_pm_callback(card, snd_ymfpci_suspend, snd_ymfpci_resume, chip);
 #endif
 
 	snd_ymfpci_proc_init(card, chip);
--- diff/sound/pcmcia/Kconfig	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pcmcia/Kconfig	2004-05-27 18:34:20.000000000 +0100
@@ -20,6 +20,7 @@
 config SND_PDAUDIOCF
 	tristate "Sound Core PDAudioCF"
 	depends on SND && PCMCIA && ISA
+	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Sound Core PDAudioCF soundcard.
 
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf.c	2004-05-27 18:34:20.000000000 +0100
@@ -21,6 +21,7 @@
 #include <sound/driver.h>
 #include <sound/core.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <pcmcia/version.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/cisreg.h>
@@ -44,19 +45,20 @@
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable switches */
 static unsigned int irq_mask = 0xffff;
 static int irq_list[4] = { -1 };
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(irq_mask, "i");
+module_param(irq_mask, int, 0444);
 MODULE_PARM_DESC(irq_mask, "IRQ bitmask for " CARD_NAME " soundcard.");
-MODULE_PARM(irq_list, "1-4i");
+module_param_array(irq_list, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq_list, "List of Available interrupts for " CARD_NAME " soundcard.");
  
 
@@ -242,10 +244,7 @@
 	if (err < 0)
 		return err;
 
-#ifdef CONFIG_PM
-	card->power_state_private_data = pdacf;
-	card->set_power_state = snd_pdacf_set_power_state;
-#endif
+	snd_card_set_pm_callback(card, snd_pdacf_suspend, snd_pdacf_resume, pdacf);
 
 	if ((err = snd_card_register(card)) < 0)
 		return err;
@@ -370,7 +369,7 @@
 		link->state |= DEV_SUSPEND;
 		if (chip) {
 			snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n");
-			snd_pdacf_suspend(chip);
+			snd_pdacf_suspend(chip->card, 0);
 		}
 		/* Fall through... */
 	case CS_EVENT_RESET_PHYSICAL:
@@ -389,7 +388,7 @@
 			pcmcia_request_configuration(link->handle, &link->conf);
 			if (chip) {
 				snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n");
-				snd_pdacf_resume(chip);
+				snd_pdacf_resume(chip->card, 0);
 			}
 		}
 		snd_printdd(KERN_DEBUG "resume done!\n");
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf.h	2004-05-27 18:34:20.000000000 +0100
@@ -136,12 +136,11 @@
 int snd_pdacf_ak4117_create(pdacf_t *pdacf);
 void snd_pdacf_powerdown(pdacf_t *chip);
 #ifdef CONFIG_PM
-void snd_pdacf_suspend(pdacf_t *chip);
-void snd_pdacf_resume(pdacf_t *chip);
-int snd_pdacf_set_power_state(snd_card_t *card, unsigned int power_state);
+int snd_pdacf_suspend(snd_card_t *card, unsigned int state);
+int snd_pdacf_resume(snd_card_t *card, unsigned int state);
 #endif
 int snd_pdacf_pcm_new(pdacf_t *chip);
-void pdacf_interrupt(int irq, void *dev, struct pt_regs *regs);
+irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs);
 void pdacf_tasklet(unsigned long private_data);
 void pdacf_reinit(pdacf_t *chip, int resume);
 
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf_core.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf_core.c	2004-05-27 18:34:20.000000000 +0100
@@ -255,13 +255,11 @@
 
 #ifdef CONFIG_PM
 
-void snd_pdacf_suspend(pdacf_t *chip)
+int snd_pdacf_suspend(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	pdacf_t *chip = snd_magic_cast(pdacf_t, card->pm_private_data, return -EINVAL);
 	u16 val;
 	
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
 	snd_pcm_suspend_all(chip->pcm);
 	/* disable interrupts, but use direct write to preserve old register value in chip->regmap */
 	val = inw(chip->port + PDAUDIOCF_REG_IER);
@@ -270,6 +268,7 @@
 	chip->chip_status |= PDAUDIOCF_STAT_IS_SUSPENDED;	/* ignore interrupts from now */
 	snd_pdacf_powerdown(chip);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
 static inline int check_signal(pdacf_t *chip)
@@ -277,13 +276,11 @@
 	return (chip->ak4117->rcs0 & AK4117_UNLCK) == 0;
 }
 
-void snd_pdacf_resume(pdacf_t *chip)
+int snd_pdacf_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
+	pdacf_t *chip = snd_magic_cast(pdacf_t, card->pm_private_data, return -EINVAL);
 	int timeout = 40;
 
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
 	pdacf_reinit(chip, 1);
 	/* wait for AK4117's PLL */
 	while (timeout-- > 0 &&
@@ -291,26 +288,6 @@
 		mdelay(1);
 	chip->chip_status &= ~PDAUDIOCF_STAT_IS_SUSPENDED;
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-int snd_pdacf_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	pdacf_t *chip = snd_magic_cast(pdacf_t, card->power_state_private_data, return -ENXIO);
-
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		snd_pdacf_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		snd_pdacf_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
-
 #endif
--- diff/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c	2004-05-27 18:34:20.000000000 +0100
@@ -26,15 +26,15 @@
 /*
  *
  */
-void pdacf_interrupt(int irq, void *dev, struct pt_regs *regs)
+irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
-	pdacf_t *chip = snd_magic_cast(pdacf_t, dev, return);
+	pdacf_t *chip = snd_magic_cast(pdacf_t, dev, return IRQ_NONE);
 	unsigned short stat;
 
 	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
 				  PDAUDIOCF_STAT_IS_CONFIGURED|
 				  PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
-		return;
+		return IRQ_HANDLED;	/* IRQ_NONE here? */
 
 	stat = inw(chip->port + PDAUDIOCF_REG_ISR);
 	if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
@@ -47,6 +47,7 @@
 	}
 	if (regs != NULL)
 		snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
+	return IRQ_HANDLED;
 }
 
 static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
--- diff/sound/pcmcia/vx/vxpocket.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pcmcia/vx/vxpocket.c	2004-05-27 18:34:20.000000000 +0100
@@ -32,6 +32,7 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <pcmcia/version.h>
 #include "vxpocket.h"
@@ -58,21 +59,22 @@
 static unsigned int irq_mask = 0xffff;
 static int irq_list[4] = { -1 };
 static int ibl[SNDRV_CARDS];
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(irq_mask, "i");
+module_param(irq_mask, int, 0444);
 MODULE_PARM_DESC(irq_mask, "IRQ bitmask for " CARD_NAME " soundcard.");
-MODULE_PARM(irq_list, "1-4i");
+module_param_array(irq_list, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq_list, "List of Available interrupts for " CARD_NAME " soundcard.");
-MODULE_PARM(ibl, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(ibl, int, boot_devs, 0444);
 MODULE_PARM_DESC(ibl, "Capture IBL size for " CARD_NAME " soundcard.");
 MODULE_PARM_SYNTAX(ibl, SNDRV_ENABLED);
  
--- diff/sound/ppc/keywest.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/ppc/keywest.c	2004-05-27 18:34:20.000000000 +0100
@@ -79,12 +79,7 @@
 
 	new_client->id = keywest_ctx->id++; /* Automatically unique */
 	keywest_ctx->client = new_client;
-
-	if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) {
-		snd_printk(KERN_ERR "tumbler: cannot initialize the MCS\n");
-		goto __err;
-	}
-
+	
 	/* Tell the i2c layer a new client has arrived */
 	if (i2c_attach_client(new_client)) {
 		snd_printk(KERN_ERR "tumbler: cannot attach i2c client\n");
@@ -121,6 +116,17 @@
 	}
 }
 
+int __init snd_pmac_tumbler_post_init(void)
+{
+	int err;
+	
+	if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) {
+		snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err);
+		return err;
+	}
+	return 0;
+}
+
 /* exported */
 int __init snd_pmac_keywest_init(pmac_keywest_t *i2c)
 {
--- diff/sound/ppc/pmac.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/ppc/pmac.c	2004-05-27 18:34:20.000000000 +0100
@@ -42,7 +42,8 @@
 #if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
 static int snd_pmac_register_sleep_notifier(pmac_t *chip);
 static int snd_pmac_unregister_sleep_notifier(pmac_t *chip);
-static int snd_pmac_set_power_state(snd_card_t *card, unsigned int power_state);
+static int snd_pmac_suspend(snd_card_t *card, unsigned int state);
+static int snd_pmac_resume(snd_card_t *card, unsigned int state);
 #endif
 
 
@@ -687,7 +688,7 @@
 static irqreturn_t
 snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, devid, return);
+	pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE);
 	snd_pmac_pcm_update(chip, &chip->playback);
 	return IRQ_HANDLED;
 }
@@ -696,7 +697,7 @@
 static irqreturn_t
 snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, devid, return);
+	pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE);
 	snd_pmac_pcm_update(chip, &chip->capture);
 	return IRQ_HANDLED;
 }
@@ -705,7 +706,7 @@
 static irqreturn_t
 snd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, devid, return);
+	pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE);
 	int ctrl = in_le32(&chip->awacs->control);
 
 	/*printk("pmac: control interrupt.. 0x%x\n", ctrl);*/
@@ -1170,9 +1171,8 @@
 
 #if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
 	/* add sleep notifier */
-	snd_pmac_register_sleep_notifier(chip);
-	card->set_power_state = snd_pmac_set_power_state;
-	card->power_state_private_data = chip;
+	if (! snd_pmac_register_sleep_notifier(chip))
+		snd_card_set_pm_callback(chip->card, snd_pmac_suspend, snd_pmac_resume, chip);
 #endif
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
@@ -1197,13 +1197,10 @@
  * Save state when going to sleep, restore it afterwards.
  */
 
-static void snd_pmac_suspend(pmac_t *chip)
+static int snd_pmac_suspend(snd_card_t *card, unsigned int state)
 {
+	pmac_t *chip = snd_magic_cast(pmac_t, card->pm_private_data, return -EINVAL);
 	unsigned long flags;
-	snd_card_t *card = chip->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D3hot)
-		return;
 
 	if (chip->suspend)
 		chip->suspend(chip);
@@ -1219,14 +1216,12 @@
 		disable_irq(chip->rx_irq);
 	snd_pmac_sound_feature(chip, 0);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	return 0;
 }
 
-static void snd_pmac_resume(pmac_t *chip)
+static int snd_pmac_resume(snd_card_t *card, unsigned int state)
 {
-	snd_card_t *card = chip->card;
-
-	if (card->power_state == SNDRV_CTL_POWER_D0)
-		return;
+	pmac_t *chip = snd_magic_cast(pmac_t, card->pm_private_data, return -EINVAL);
 
 	snd_pmac_sound_feature(chip, 1);
 	if (chip->resume)
@@ -1248,6 +1243,7 @@
 		enable_irq(chip->rx_irq);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return 0;
 }
 
 /* the chip is stored statically by snd_pmac_register_sleep_notifier
@@ -1264,10 +1260,10 @@
 
 	switch (when) {
 	case PBOOK_SLEEP_NOW:
-		snd_pmac_suspend(chip);
+		snd_pmac_suspend(chip->card, 0);
 		break;
 	case PBOOK_WAKE:
-		snd_pmac_resume(chip);
+		snd_pmac_resume(chip->card, 0);
 		break;
 	}
 	return PBOOK_SLEEP_OK;
@@ -1280,46 +1276,19 @@
 static int __init snd_pmac_register_sleep_notifier(pmac_t *chip)
 {
 	/* should be protected here.. */
-	if (sleeping_pmac) {
-		snd_printd("sleep notifier already reigistered\n");
-		return -EBUSY;
-	}
+	snd_assert(! sleeping_pmac, return -EBUSY);
 	sleeping_pmac = chip;
 	pmu_register_sleep_notifier(&snd_pmac_sleep_notifier);
-	chip->sleep_registered = 1;
 	return 0;
 }
 						    
 static int snd_pmac_unregister_sleep_notifier(pmac_t *chip)
 {
-	if (! chip->sleep_registered)
-		return 0;
 	/* should be protected here.. */
-	if (sleeping_pmac != chip)
-		return -ENODEV;
+	snd_assert(sleeping_pmac == chip, return -ENODEV);
 	pmu_unregister_sleep_notifier(&snd_pmac_sleep_notifier);
 	sleeping_pmac = NULL;
 	return 0;
 }
 
-/* callback */
-static int snd_pmac_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-	pmac_t *chip = snd_magic_cast(pmac_t, card->power_state_private_data, return -ENXIO);
-	switch (power_state) {
-	case SNDRV_CTL_POWER_D0:
-	case SNDRV_CTL_POWER_D1:
-	case SNDRV_CTL_POWER_D2:
-		snd_pmac_resume(chip);
-		break;
-	case SNDRV_CTL_POWER_D3hot:
-	case SNDRV_CTL_POWER_D3cold:
-		snd_pmac_suspend(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
 #endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */
--- diff/sound/ppc/pmac.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/ppc/pmac.h	2004-05-27 18:34:20.000000000 +0100
@@ -162,7 +162,6 @@
 	void (*update_automute)(pmac_t *chip, int do_notify);
 	int (*detect_headphone)(pmac_t *chip);
 #ifdef CONFIG_PMAC_PBOOK
-	unsigned int sleep_registered : 1;
 	void (*suspend)(pmac_t *chip);
 	void (*resume)(pmac_t *chip);
 #endif
@@ -180,6 +179,7 @@
 int snd_pmac_burgundy_init(pmac_t *chip);
 int snd_pmac_daca_init(pmac_t *chip);
 int snd_pmac_tumbler_init(pmac_t *chip);
+int snd_pmac_tumbler_post_init(void);
 
 /* i2c functions */
 typedef struct snd_pmac_keywest {
--- diff/sound/ppc/powermac.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/ppc/powermac.c	2004-05-27 18:34:20.000000000 +0100
@@ -20,8 +20,8 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include "pmac.h"
 #include "awacs.h"
@@ -41,17 +41,17 @@
 static int enable_beep = 1;
 #endif
 
-MODULE_PARM(index, "i");
+module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for " CHIP_NAME " soundchip.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "s");
+module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-/* MODULE_PARM(enable, "i");
+/* module_param(enable, bool, 0444);
    MODULE_PARM_DESC(enable, "Enable this soundchip.");
    MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); */
 #ifdef PMAC_SUPPORT_PCM_BEEP
-MODULE_PARM(enable_beep, "i");
+module_param(enable_beep, bool, 0444);
 MODULE_PARM_DESC(enable_beep, "Enable beep using PCM.");
 MODULE_PARM_SYNTAX(enable_beep, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
 #endif
@@ -104,7 +104,7 @@
 		sprintf(card->shortname, "PowerMac %s", name_ext);
 		sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
 			card->shortname, chip->device_id, chip->subframe);
-		if ((err = snd_pmac_tumbler_init(chip)) < 0)
+		if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0)
 			goto __error;
 		break;
 	case PMAC_AWACS:
@@ -175,26 +175,3 @@
 
 module_init(alsa_card_pmac_init)
 module_exit(alsa_card_pmac_exit)
-
-#ifndef MODULE
-
-/* format is: snd-pmac=enable,index,id,enable_beep
- */
-
-static int __init alsa_card_pmac_setup(char *str)
-{
-	int __attribute__ ((__unused__)) enable = 1;
-
-	(void)(get_option(&str,&enable) == 2 &&
-	       get_option(&str,&index) == 2 &&
-	       get_id(&str,&id) == 2
-#ifdef PMAC_SUPPORT_PCM_BEEP
-	       && get_option(&str,&enable_beep) == 2
-#endif
-	       );
-	return 1;
-}
-
-__setup("snd-pmac=", alsa_card_pmac_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/ppc/tumbler.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/ppc/tumbler.c	2004-05-27 18:34:20.000000000 +0100
@@ -684,6 +684,8 @@
 
 static int snapper_set_capture_source(pmac_tumbler_t *mix)
 {
+	if (! mix->i2c.client)
+		return -ENODEV;
 	return snd_pmac_keywest_write_byte(&mix->i2c, TAS_REG_ACS,
 					   mix->capture_source ? 2 : 0);
 }
@@ -870,7 +872,7 @@
 /* interrupt - headphone plug changed */
 static irqreturn_t headphone_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, devid, return);
+	pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE);
 	if (chip->update_automute && chip->initialized) {
 		chip->update_automute(chip, 1);
 		return IRQ_HANDLED;
--- diff/sound/sparc/amd7930.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/sparc/amd7930.c	2004-05-27 18:34:20.000000000 +0100
@@ -34,13 +34,13 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/moduleparam.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
 #include <sound/control.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include <asm/io.h>
@@ -50,14 +50,15 @@
 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 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Sun AMD7930 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Sun AMD7930 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Sun AMD7930 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 MODULE_AUTHOR("Thomas K. Dyas and David S. Miller");
@@ -1152,24 +1153,3 @@
 
 module_init(amd7930_init);
 module_exit(amd7930_exit);
-
-#ifndef MODULE
-
-/* format is: snd-sun-amd7930=index,id,enable */
-
-static int __init alsa_card_sun_amd7930_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str,&index[nr_dev]) == 2 &&
-	       get_option(&str,&id[nr_dev]) == 2 &&
-	       get_id(&str,&enable[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-sun-amd7930=", alsa_card_sun_amd7930_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/sparc/cs4231.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/sparc/cs4231.c	2004-05-27 18:34:20.000000000 +0100
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/moduleparam.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -22,7 +23,6 @@
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/timer.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 #include <sound/pcm_params.h>
 
@@ -49,14 +49,15 @@
 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 */
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for Sun CS4231 soundcard.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable Sun CS4231 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
 MODULE_AUTHOR("Jaroslav Kysela, Derrick J. Brashear and David S. Miller");
@@ -2251,24 +2252,3 @@
 
 module_init(cs4231_init);
 module_exit(cs4231_exit);
-
-#ifndef MODULE
-
-/* format is: snd-sun-cs4231=index,id,enable */
-
-static int __init alsa_card_sun_cs4231_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str,&index[nr_dev]) == 2 &&
-	       get_option(&str,&id[nr_dev]) == 2 &&
-	       get_id(&str,&enable[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-sun-cs4231=", alsa_card_sun_cs4231_setup);
-
-#endif /* ifndef MODULE */
--- diff/sound/usb/usbaudio.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/usb/usbaudio.c	2004-05-27 18:34:20.000000000 +0100
@@ -45,11 +45,11 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/usb.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include "usbaudio.h"
@@ -69,26 +69,27 @@
 static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
 static int nrpacks = 4;		/* max. number of packets per urb */
 static int async_unlink = 1;
+static int boot_devs;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, boot_devs, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, boot_devs, 0444);
 MODULE_PARM_DESC(id, "ID string for the USB audio adapter.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable USB audio adapter.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(vid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(vid, int, boot_devs, 0444);
 MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
 MODULE_PARM_SYNTAX(vid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
-MODULE_PARM(pid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pid, int, boot_devs, 0444);
 MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
 MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
-MODULE_PARM(nrpacks, "i");
+module_param(nrpacks, int, 0444);
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
 MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{1,10}}");
-MODULE_PARM(async_unlink, "i");
+module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
 MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC);
 
@@ -1146,7 +1147,7 @@
 	/* if endpoint has pitch control, enable it */
 	if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) {
 		data[0] = 1;
-		if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+		if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
 					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
 					   PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
 			snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
@@ -1172,14 +1173,14 @@
 		data[0] = rate;
 		data[1] = rate >> 8;
 		data[2] = rate >> 16;
-		if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+		if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
 					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
 					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
 			snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep 0x%x\n",
 				   dev->devnum, iface, fmt->altsetting, rate, ep);
 			return err;
 		}
-		if ((err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
+		if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
 					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
 					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
 			snd_printk(KERN_ERR "%d:%d:%d: cannot get freq at ep 0x%x\n",
@@ -1231,7 +1232,7 @@
 				   dev->devnum, fmt->iface, fmt->altsetting);
 			return -EIO;
 		}
-		snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altset_idx);
+		snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting);
 		subs->interface = fmt->iface;
 		subs->format = fmt->altset_idx;
 	}
@@ -1884,6 +1885,32 @@
 	return NULL;
 }
 
+/*
+ * Wrapper for usb_control_msg().
+ * Allocates a temp buffer to prevent dmaing from/to the stack.
+ */
+int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
+		    __u8 requesttype, __u16 value, __u16 index, void *data,
+		    __u16 size, int timeout)
+{
+	int err;
+	void *buf = NULL;
+
+	if (size > 0) {
+		buf = kmalloc(size, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+		memcpy(buf, data, size);
+	}
+	err = usb_control_msg(dev, pipe, request, requesttype,
+			      value, index, buf, size, timeout);
+	if (size > 0) {
+		memcpy(data, buf, size);
+		kfree(buf);
+	}
+	return err;
+}
+
 
 /*
  * entry point for linux usb interface
@@ -1926,7 +1953,7 @@
 		struct audioformat *fp;
 		fp = list_entry(p, struct audioformat, list);
 		snd_iprintf(buffer, "  Interface %d\n", fp->iface);
-		snd_iprintf(buffer, "    Altset %d\n", fp->altset_idx);
+		snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
 		snd_iprintf(buffer, "    Format: %s\n", snd_pcm_format_name(fp->format));
 		snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
 		snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
@@ -2640,6 +2667,7 @@
 	struct audioformat *fp;
 	struct usb_host_interface *alts;
 	int stream, err;
+	int *rate_table = NULL;
 
 	fp = kmalloc(sizeof(*fp), GFP_KERNEL);
 	if (! fp) {
@@ -2647,16 +2675,30 @@
 		return -ENOMEM;
 	}
 	memcpy(fp, quirk->data, sizeof(*fp));
+	if (fp->nr_rates > 0) {
+		rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL);
+		if (!rate_table) {
+			kfree(fp);
+			return -ENOMEM;
+		}
+		memcpy(rate_table, fp->rate_table, sizeof(int) * fp->nr_rates);
+		fp->rate_table = rate_table;
+	}
+
 	stream = (fp->endpoint & USB_DIR_IN)
 		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
 	err = add_audio_endpoint(chip, stream, fp);
 	if (err < 0) {
 		kfree(fp);
+		if (rate_table)
+			kfree(rate_table);
 		return err;
 	}
 	if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
 	    fp->altset_idx >= iface->num_altsetting) {
 		kfree(fp);
+		if (rate_table)
+			kfree(rate_table);
 		return -EINVAL;
 	}
 	alts = &iface->altsetting[fp->altset_idx];
@@ -2700,6 +2742,83 @@
 	return 0;
 }
 
+/*
+ * Create a stream for an Edirol UA-700 interface.  The only way
+ * to detect the sample rate is by looking at wMaxPacketSize.
+ */
+static int create_ua700_quirk(snd_usb_audio_t *chip, struct usb_interface *iface)
+{
+	static const struct audioformat ua700_format = {
+		.format = SNDRV_PCM_FORMAT_S24_3LE,
+		.channels = 2,
+		.fmt_type = USB_FORMAT_TYPE_I,
+		.altsetting = 1,
+		.altset_idx = 1,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+	};
+	struct usb_host_interface *alts;
+	struct usb_interface_descriptor *altsd;
+	struct audioformat *fp;
+	int stream, err;
+
+	/* both PCM and MIDI interfaces have 2 altsettings */
+	if (iface->num_altsetting != 2)
+		return -ENXIO;
+	alts = &iface->altsetting[1];
+	altsd = get_iface_desc(alts);
+
+	if (altsd->bNumEndpoints == 2) {
+		static const snd_usb_midi_endpoint_info_t ep = {
+			.out_cables = 0x0003,
+			.in_cables  = 0x0003
+		};
+		static const snd_usb_audio_quirk_t quirk = {
+			.type = QUIRK_MIDI_FIXED_ENDPOINT,
+			.data = &ep
+		};
+		return snd_usb_create_midi_interface(chip, iface, &quirk);
+	}
+
+	if (altsd->bNumEndpoints != 1)
+		return -ENXIO;
+
+	fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+	if (!fp)
+		return -ENOMEM;
+	memcpy(fp, &ua700_format, sizeof(*fp));
+
+	fp->iface = altsd->bInterfaceNumber;
+	fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
+	fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+	fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
+
+	switch (fp->maxpacksize) {
+	case 0x120:
+		fp->rate_max = fp->rate_min = 44100;
+		break;
+	case 0x138:
+		fp->rate_max = fp->rate_min = 48000;
+		break;
+	case 0x258:
+		fp->rate_max = fp->rate_min = 96000;
+		break;
+	default:
+		snd_printk(KERN_ERR "unknown sample rate\n");
+		kfree(fp);
+		return -ENXIO;
+	}
+
+	stream = (fp->endpoint & USB_DIR_IN)
+		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+	err = add_audio_endpoint(chip, stream, fp);
+	if (err < 0) {
+		kfree(fp);
+		return err;
+	}
+	usb_set_interface(chip->dev, fp->iface, 0);
+	return 0;
+}
+
 static int snd_usb_create_quirk(snd_usb_audio_t *chip,
 				struct usb_interface *iface,
 				const snd_usb_audio_quirk_t *quirk);
@@ -2747,7 +2866,7 @@
 	    get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_NEW) {
 		snd_printdd("sending Extigy boot sequence...\n");
 		/* Send message to force it to reconnect with full interface. */
-		err = usb_control_msg(dev, usb_sndctrlpipe(dev,0),
+		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
 				      0x10, 0x43, 0x0001, 0x000a, NULL, 0, HZ);
 		if (err < 0) snd_printdd("error sending boot message: %d\n", err);
 		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
@@ -2787,6 +2906,8 @@
 	case QUIRK_AUDIO_STANDARD_INTERFACE:
 	case QUIRK_MIDI_STANDARD_INTERFACE:
 		return create_standard_interface_quirk(chip, iface, quirk);
+	case QUIRK_AUDIO_EDIROL_UA700:
+		return create_ua700_quirk(chip, iface);
 	default:
 		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 		return -ENXIO;
@@ -3124,26 +3245,3 @@
 
 module_init(snd_usb_audio_init);
 module_exit(snd_usb_audio_cleanup);
-
-#ifndef MODULE
-/*
- * format is snd-usb-audio=enable,index,id,vid,pid
- */
-static int __init snd_usb_audio_module_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 &&
-	       get_option(&str, &vid[nr_dev]) == 2 &&
-	       get_option(&str, &pid[nr_dev]) == 2);
-	++nr_dev;
-	return 1;
-}
-
-__setup("snd-usb-audio=", snd_usb_audio_module_setup);
-
-#endif /* !MODULE */
--- diff/sound/usb/usbaudio.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/usb/usbaudio.h	2004-05-27 18:34:20.000000000 +0100
@@ -154,6 +154,7 @@
 #define QUIRK_AUDIO_FIXED_ENDPOINT	4
 #define QUIRK_AUDIO_STANDARD_INTERFACE	5
 #define QUIRK_MIDI_STANDARD_INTERFACE	6
+#define QUIRK_AUDIO_EDIROL_UA700	7
 
 typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
 typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
@@ -185,6 +186,8 @@
 
 /* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */
 
+/* for QUIRK_AUDIO_EDIROL_UA700, data is NULL */
+
 /*
  */
 
@@ -197,6 +200,8 @@
 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_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
+
 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);
--- diff/sound/usb/usbmixer.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/usb/usbmixer.c	2004-05-27 18:34:20.000000000 +0100
@@ -301,7 +301,7 @@
 	int timeout = 10;
  
 	while (timeout-- > 0) {
-		if (usb_control_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0),
+		if (snd_usb_ctl_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0),
 				    request,
 				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
 				    validx, cval->ctrlif | (cval->id << 8),
@@ -339,7 +339,7 @@
 	buf[0] = value_set & 0xff;
 	buf[1] = (value_set >> 8) & 0xff;
 	while (timeout -- > 0)
-		if (usb_control_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0),
+		if (snd_usb_ctl_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0),
 				    request,
 				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
 				    validx, cval->ctrlif | (cval->id << 8),
--- diff/sound/usb/usbquirks.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/usb/usbquirks.h	2004-05-27 18:34:20.000000000 +0100
@@ -113,7 +113,7 @@
 		.product_name = "UA-100",
 		.ifnum = QUIRK_ANY_INTERFACE,
 		.type = QUIRK_COMPOSITE,
-		.data = & (const snd_usb_audio_quirk_t[]) {
+		.data = (const snd_usb_audio_quirk_t[]) {
 			{
 				.ifnum = 0,
 				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
@@ -274,7 +274,7 @@
 		.product_name = "SC-D70",
 		.ifnum = QUIRK_ANY_INTERFACE,
 		.type = QUIRK_COMPOSITE,
-		.data = & (const snd_usb_audio_quirk_t[]) {
+		.data = (const snd_usb_audio_quirk_t[]) {
 			{
 				.ifnum = 0,
 				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
@@ -338,7 +338,7 @@
 		.product_name = "UA-5",
 		.ifnum = QUIRK_ANY_INTERFACE,
 		.type = QUIRK_COMPOSITE,
-		.data = & (const snd_usb_audio_quirk_t[]) {
+		.data = (const snd_usb_audio_quirk_t[]) {
 			{
 				.ifnum = 1,
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
@@ -443,7 +443,7 @@
 		.product_name = "UA-20",
 		.ifnum = QUIRK_ANY_INTERFACE,
 		.type = QUIRK_COMPOSITE,
-		.data = & (const snd_usb_audio_quirk_t[]) {
+		.data = (const snd_usb_audio_quirk_t[]) {
 			{
 				.ifnum = 1,
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
@@ -488,16 +488,34 @@
 		}
 	}
 },
-{
+{	/*
+	 * This quirk is for the "Advanced" modes of the Edirol UA-700.
+	 * If the sample format switch is not in an advanced setting, the
+	 * UA-700 has ID 0x0582/0x002c and is standard compliant (no quirks),
+	 * but offers only 16-bit PCM and no MIDI.
+	 */
 	USB_DEVICE_VENDOR_SPEC(0x0582, 0x002b),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "UA-700",
-		.ifnum = 3,
-		.type = QUIRK_MIDI_FIXED_ENDPOINT,
-		.data = & (const snd_usb_midi_endpoint_info_t) {
-			.out_cables = 0x0003,
-			.in_cables  = 0x0003
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_EDIROL_UA700
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_EDIROL_UA700
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_AUDIO_EDIROL_UA700
+			},
+			{
+				.ifnum = -1
+			}
 		}
 	}
 },
@@ -580,6 +598,62 @@
 	}
 },
 {
+	USB_DEVICE(0x0582, 0x0044),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "UA-1000",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = & (const struct audioformat) {
+					.format = SNDRV_PCM_FORMAT_S24,
+					.channels = 12,
+					.iface = 1,
+					.altsetting = 1,
+					.altset_idx = 1,
+					.attributes = 0,
+					.endpoint = 0x81,
+					.ep_attr = 0x01,
+					.rates = SNDRV_PCM_RATE_CONTINUOUS,
+					.rate_min = 48000,
+					.rate_max = 48000,
+				}
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = & (const struct audioformat) {
+					.format = SNDRV_PCM_FORMAT_S24,
+					.channels = 10,
+					.iface = 2,
+					.altsetting = 1,
+					.altset_idx = 1,
+					.attributes = 0,
+					.endpoint = 0x02,
+					.ep_attr = 0x01,
+					.rates = SNDRV_PCM_RATE_CONTINUOUS,
+					.rate_min = 48000,
+					.rate_max = 48000,
+				}
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_MIDI_FIXED_ENDPOINT,
+				.data = & (const snd_usb_midi_endpoint_info_t) {
+					.out_cables = 0x0003,
+					.in_cables  = 0x0003
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
 	USB_DEVICE(0x0582, 0x0048),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
@@ -629,7 +703,7 @@
 		.product_name = "UA-3FX",
 		.ifnum = QUIRK_ANY_INTERFACE,
 		.type = QUIRK_COMPOSITE,
-		.data = & (const snd_usb_audio_quirk_t[]) {
+		.data = (const snd_usb_audio_quirk_t[]) {
 			{
 				.ifnum = 1,
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
--- diff/Documentation/hpet.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/hpet.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,298 @@
+		High Precision Event Timer Driver for Linux
+
+The High Precision Event Timer (HPET) hardware is the future replacement for the 8254 and Real
+Time Clock (RTC) periodic timer functionality.  Each HPET can have up two 32 timers.  It is possible
+to configure the first two timers as legacy replacements for 8254 and RTC periodic.  A specification
+done by INTEL and Microsoft can be found at http://www.intel.com/labs/platcomp/hpet/hpetspec.htm.
+
+The driver supports detection of HPET driver allocation and initialization of the HPET before the
+driver module_init routine is called.  This enables platform code which uses timer 0 or 1 as the
+main timer to intercept HPET initialization.  An example of this initialization can be found in
+arch/i386/kernel/time_hpet.c.
+
+The driver provides two APIs which are very similar to the API found in the rtc.c driver.
+There is a user space API and a kernel space API.  An example user space program is provided
+below.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <malloc.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <linux/hpet.h>
+
+
+extern void hpet_open_close(int, const char **);
+extern void hpet_info(int, const char **);
+extern void hpet_poll(int, const char **);
+extern void hpet_fasync(int, const char **);
+extern void hpet_read(int, const char **);
+
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+
+struct hpet_command {
+	char		*command;
+	void		(*func)(int argc, const char ** argv);
+} hpet_command[] = {
+	{
+		"open-close",
+		hpet_open_close
+	},
+	{
+		"info",
+		hpet_info
+	},
+	{
+		"poll",
+		hpet_poll
+	},
+	{
+		"fasync",
+		hpet_fasync
+	},
+};
+
+int
+main(int argc, const char ** argv)
+{
+	int	i;
+
+	argc--;
+	argv++;
+
+	if (!argc) {
+		fprintf(stderr, "-hpet: requires command\n");
+		return -1;
+	}
+
+
+	for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
+		if (!strcmp(argv[0], hpet_command[i].command)) {
+			argc--;
+			argv++;
+			fprintf(stderr, "-hpet: executing %s\n",
+				hpet_command[i].command);
+			hpet_command[i].func(argc, argv);
+			return 0;
+		}
+
+	fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
+
+	return -1;
+}
+
+void
+hpet_open_close(int argc, const char **argv)
+{
+	int	fd;
+
+	if (argc != 1) {
+		fprintf(stderr, "hpet_open_close: device-name\n");
+		return;
+	}
+
+	fd = open(argv[0], O_RDWR);
+	if (fd < 0)
+		fprintf(stderr, "hpet_open_close: open failed\n");
+	else
+		close(fd);
+
+	return;
+}
+
+void
+hpet_info(int argc, const char **argv)
+{
+}
+
+void
+hpet_poll(int argc, const char **argv)
+{
+	unsigned long		freq;
+	int			iterations, i, fd;
+	struct pollfd		pfd;
+	struct hpet_info	info;
+	struct timeval		stv, etv;
+	struct timezone		tz;
+	long			usec;
+
+	if (argc != 3) {
+		fprintf(stderr, "hpet_poll: device-name freq iterations\n");
+		return;
+	}
+
+	freq = atoi(argv[1]);
+	iterations = atoi(argv[2]);
+
+	fd = open(argv[0], O_RDWR);
+
+	if (fd < 0) {
+		fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
+		return;
+	}
+
+	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
+		fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_INFO, &info) < 0) {
+		fprintf(stderr, "hpet_poll: failed to get info\n");
+		goto out;
+	}
+
+	fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
+
+	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
+		fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
+		fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
+		goto out;
+	}
+
+	pfd.fd = fd;
+	pfd.events = POLLIN;
+
+	for (i = 0; i < iterations; i++) {
+		pfd.revents = 0;
+		gettimeofday(&stv, &tz);
+		if (poll(&pfd, 1, -1) < 0)
+			fprintf(stderr, "hpet_poll: poll failed\n");
+		else {
+			long 	data;
+
+			gettimeofday(&etv, &tz);
+			usec = stv.tv_sec * 1000000 + stv.tv_usec;
+			usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
+
+			fprintf(stderr,
+				"hpet_poll: expired time = 0x%lx\n", usec);
+
+			fprintf(stderr, "hpet_poll: revents = 0x%x\n",
+				pfd.revents);
+
+			if (read(fd, &data, sizeof(data)) != sizeof(data)) {
+				fprintf(stderr, "hpet_poll: read failed\n");
+			}
+			else
+				fprintf(stderr, "hpet_poll: data 0x%lx\n",
+					data);
+		}
+	}
+
+out:
+	close(fd);
+	return;
+}
+
+static int hpet_sigio_count;
+
+static void
+hpet_sigio(int val)
+{
+	fprintf(stderr, "hpet_sigio: called\n");
+	hpet_sigio_count++;
+}
+
+void
+hpet_fasync(int argc, const char **argv)
+{
+	unsigned long		freq;
+	int			iterations, i, fd, value;
+	sig_t			oldsig;
+	struct hpet_info	info;
+
+	hpet_sigio_count = 0;
+	fd = -1;
+
+	if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
+		fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
+		return;
+	}
+
+	if (argc != 3) {
+		fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
+		goto out;
+	}
+
+	fd = open(argv[0], O_RDWR);
+
+	if (fd < 0) {
+		fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
+		return;
+	}
+
+
+	if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
+		((value = fcntl(fd, F_GETFL)) == 1) ||
+		(fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
+		fprintf(stderr, "hpet_fasync: fcntl failed\n");
+		goto out;
+	}
+
+	freq = atoi(argv[1]);
+	iterations = atoi(argv[2]);
+
+	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
+		fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_INFO, &info) < 0) {
+		fprintf(stderr, "hpet_fasync: failed to get info\n");
+		goto out;
+	}
+
+	fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
+
+	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
+		fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
+		fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
+		goto out;
+	}
+
+	for (i = 0; i < iterations; i++) {
+		(void) pause();
+		fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
+	}
+
+out:
+	signal(SIGIO, oldsig);
+
+	if (fd >= 0)
+		close(fd);
+
+	return;
+}
+
+The kernel API has three interfaces exported from the driver:
+
+	hpet_register(struct hpet_task *tp, int periodic)
+	hpet_unregister(struct hpet_task *tp)
+	hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
+
+The kernel module using this interface fills in the ht_func and ht_data members of the
+hpet_task structure before calling hpet_register.  hpet_control simply vectors to the hpet_ioctl
+routine and has the same commands and respective arguments as the user API.  hpet_unregister
+is used to terminate usage of the HPET timer reserved by hpet_register.
+
+
--- diff/Documentation/i386/kgdb/andthen	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/andthen	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,100 @@
+
+define	set_andthen
+	set var $thp=0
+	set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0]
+	set var $at_size = (sizeof kgdb_data)/(sizeof *$thp)
+	set var $at_oc=kgdb_and_then_count
+	set var $at_cc=$at_oc
+end
+
+define andthen_next
+	set var $at_cc=$arg0
+end
+
+define andthen
+	andthen_set_edge
+	if ($at_cc >= $at_oc)
+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
+	else
+		printf "%d: ",$at_cc
+		output *($thp+($at_cc++ % $at_size ))
+		printf "\n"
+	end
+end
+define andthen_set_edge
+	set var $at_oc=kgdb_and_then_count
+	set var $at_low = $at_oc - $at_size
+	if ($at_low < 0 )
+		set var $at_low = 0
+	end
+	if (( $at_cc > $at_oc) || ($at_cc < $at_low))
+		printf "Count outside of window, setting count to "
+		if ($at_cc >= $at_oc)
+			set var $at_cc = $at_oc
+		else
+			set var $at_cc = $at_low
+		end
+		printf "%d\n",$at_cc
+	end
+end
+
+define beforethat
+	andthen_set_edge
+	if ($at_cc <= $at_low)
+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
+	else
+		printf "%d: ",$at_cc-1
+		output *($thp+(--$at_cc % $at_size ))
+		printf "\n"
+	end
+end
+
+document andthen_next
+	andthen_next <count>
+	.	sets the number of the event to display next. If this event
+	.	is not in the event pool, either andthen or beforethat will
+	.	correct it to the nearest event pool edge.  The event pool
+	.	ends at the last event recorded and begins <number of events>
+	.	prior to that.  If beforethat is used next, it will display
+	.	event <count> -1.
+.
+	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+
+document andthen
+	andthen
+.	displays the next event in the list.  <set_andthen> sets up to display
+.	the oldest saved event first.
+.	<count> (optional) count of the event to display.
+.	note the number of events saved is specified at configure time.
+.	if events are saved between calls to andthen the index will change
+.	but the displayed event will be the next one (unless the event buffer
+.	is overrun).
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+document set_andthen
+	set_andthen
+.	sets up to use the <andthen> and <beforethat> commands.
+.		if you have defined your own struct, use the above and
+.		then enter the following:
+.		p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0]
+.		where <kgdb_and_then_structX> is the name of your structure.
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+document beforethat
+	beforethat
+.	displays the next prior event in the list. <set_andthen> sets up to
+.	display the last occuring event first.
+.
+.	note the number of events saved is specified at configure time.
+.	if events are saved between calls to beforethat the index will change
+.	but the displayed event will be the next one (unless the event buffer
+.	is overrun).
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
--- diff/Documentation/i386/kgdb/debug-nmi.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/debug-nmi.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,37 @@
+Subject: Debugging with NMI
+Date: Mon, 12 Jul 1999 11:28:31 -0500
+From: David Grothe <dave@gcom.com>
+Organization: Gcom, Inc
+To: David Grothe <dave@gcom.com>
+
+Kernel hackers:
+
+Maybe this is old hat, but it is new to me --
+
+On an ISA bus machine, if you short out the A1 and B1 pins of an ISA
+slot you will generate an NMI to the CPU.  This interrupts even a
+machine that is hung in a loop with interrupts disabled.  Used in
+conjunction with kgdb <
+ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can
+gain debugger control of a machine that is hung in the kernel!  Even
+without kgdb the kernel will print a stack trace so you can find out
+where it was hung.
+
+The A1/B1 pins are directly opposite one another and the farthest pins
+towards the bracket end of the ISA bus socket.  You can stick a paper
+clip or multi-meter probe between them to short them out.
+
+I had a spare ISA bus to PC104 bus adapter around.  The PC104 end of the
+board consists of two rows of wire wrap pins.  So I wired a push button
+between the A1/B1 pins and now have an ISA board that I can stick into
+any ISA bus slot for debugger entry.
+
+Microsoft has a circuit diagram of a PCI card at
+http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM.  If you want to
+build one you will have to mail them and ask for the PAL equations.
+Nobody makes one comercially.
+
+[THIS TIP COMES WITH NO WARRANTY WHATSOEVER.  It works for me, but if
+your machine catches fire, it is your problem, not mine.]
+
+-- Dave (the kgdb guy)
--- diff/Documentation/i386/kgdb/gdb-globals.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdb-globals.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,71 @@
+Sender: akale@veritas.com
+Date: Fri, 23 Jun 2000 19:26:35 +0530
+From: "Amit S. Kale" <akale@veritas.com>
+Organization: Veritas Software (India)
+To: Dave Grothe <dave@gcom.com>, linux-kernel@vger.rutgers.edu
+CC: David Milburn <dmilburn@wirespeed.com>,
+        "Edouard G. Parmelan" <Edouard.Parmelan@quadratec.fr>,
+        ezannoni@cygnus.com, Keith Owens <kaos@ocs.com.au>
+Subject: Re: Module debugging using kgdb
+
+Dave Grothe wrote:
+>
+> Amit:
+>
+> There is a 2.4.0 version of kgdb on our ftp site:
+> ftp://ftp.gcom.com/pub/linux/src/kgdb.  I mirrored your version of gdb
+> and loadmodule.sh there.
+>
+> Have a look at the README file and see if I go it right.  If not, send
+> me some corrections and I will update it.
+>
+> Does your version of gdb solve the global variable problem?
+
+Yes.
+Thanks to Elena Zanoni, gdb (developement version) can now calculate
+correctly addresses  of dynamically loaded object files. I have not been
+following gdb developement for sometime and am not sure when symbol
+address calculation fix is going to appear in a gdb stable version.
+
+Elena, any idea when the fix will make it to a prebuilt gdb from a
+redhat release?
+
+For the time being I have built a gdb developement version. It can be
+used for module debugging with loadmodule.sh script.
+
+The problem with calculating of module addresses with previous versions
+of gdb was as follows:
+gdb did not use base address of a section while calculating address of
+a symbol in the section in an object file loaded via 'add-symbol-file'.
+It used address of .text segment instead. Due to this addresses of
+symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly.
+
+Above mentioned fix allow gdb to use base address of a segment while
+calculating address of a symbol in it. It adds a parameter '-s' to
+'add-symbol-file' command for specifying base address of a segment.
+
+loadmodule.sh script works as follows.
+
+1. Copy a module file to target machine.
+2. Load the module on the target machine using insmod with -m parameter.
+insmod produces a module load map which contains base addresses of all
+sections in the module and addresses of symbols in the module file.
+3. Find all sections and their base addresses in the module from
+the module map.
+4. Generate a script that loads the module file. The script uses
+'add-symbol-file' and specifies address of text segment followed by
+addresses of all segments in the module.
+
+Here is an example gdb script produced by loadmodule.sh script.
+
+add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5
+-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38
+-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838
+
+With this command gdb can calculate addresses of symbols in ANY segment
+in a module file.
+
+Regards.
+--
+Amit Kale
+Veritas Software ( http://www.veritas.com )
--- diff/Documentation/i386/kgdb/gdbinit	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,14 @@
+shell echo -e "\003" >/dev/ttyS0
+set remotebaud 38400
+target remote /dev/ttyS0
+define si
+stepi
+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
+x/i $eip
+end
+define ni
+nexti
+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
+x/i $eip
--- diff/Documentation/i386/kgdb/gdbinit-modules	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit-modules	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,146 @@
+#
+# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub.
+#
+# This don't work for Linux-2.0 or older.
+#
+# Author Edouard G. Parmelan <Edouard.Parmelan@quadratec.fr>
+#
+#
+# Fri Apr 30 20:33:29 CEST 1999
+#   First public release.
+#
+#   Major cleanup after experiment Linux-2.0 kernel without success.
+#   Symbols of a module are not in the correct order, I can't explain
+#   why :(
+#
+# Fri Mar 19 15:41:40 CET 1999
+#   Initial version.
+#
+# Thu Jan  6 16:29:03 CST 2000
+#   A little fixing by Dave Grothe <dave@gcom.com>
+#
+# Mon Jun 19 09:33:13 CDT 2000
+#   Alignment changes from Edouard Parmelan
+#
+# The basic idea is to find where insmod load the module and inform
+# GDB to load the symbol table of the module with the GDB command
+# ``add-symbol-file <object> <address>''.
+#
+# The Linux kernel holds the list of all loaded modules in module_list,
+# this list end with &kernel_module (exactly with module->next == NULL,
+# but the last module is not a real module).
+#
+# Insmod allocates the struct module before the object file.  Since
+# Linux-2.1, this structure contain his size.  The real address of
+# the object file is then (char*)module + module->size_of_struct.
+#
+# You can use three user functions ``mod-list'', ``mod-print-symbols''
+# and ``add-module-symbols''.
+#
+# mod-list list all loaded modules with the format:
+#    <module-address> <module-name>
+#
+# As soon as you have found the address of your module, you can
+# print its exported symbols (mod-print-symbols) or inform GDB to add
+# symbols from your module file (mod-add-symbols).
+#
+# The argument that you give to mod-print-symbols or mod-add-symbols
+# is the <module-address> from the mod-list command.
+#
+# When using the mod-add-symbols command you must also give the full
+# pathname of the modules object code file.
+#
+# The command mod-add-lis is an example of how to make this easier.
+# You can edit this macro to contain the path name of your own
+# favorite module and then use it as a shorthand to load it.  You
+# still need the module-address, however.
+#
+# The internal function ``mod-validate'' set the GDB variable $mod
+# as a ``struct module*'' if the kernel known the module otherwise
+# $mod is set to NULL.  This ensure to not add symbols for a wrong
+# address.
+#
+# Have a nice hacking day !
+#
+#
+define mod-list
+    set $mod = (struct module*)module_list
+    # the last module is the kernel, ignore it
+    while $mod != &kernel_module
+    	printf "%p\t%s\n", (long)$mod, ($mod)->name
+	set $mod = $mod->next
+    end
+end
+document mod-list
+List all modules in the form: <module-address> <module-name>
+Use the <module-address> as the argument for the other
+mod-commands: mod-print-symbols, mod-add-symbols.
+end
+
+define mod-validate
+    set $mod = (struct module*)module_list
+    while ($mod != $arg0) && ($mod != &kernel_module)
+    	set $mod = $mod->next
+    end
+    if $mod == &kernel_module
+	set $mod = 0
+    	printf "%p is not a module\n", $arg0
+    end
+end
+document mod-validate
+mod-validate <module-address>
+Internal user-command used to validate the module parameter.
+If <module> is a real loaded module, set $mod to it otherwise set $mod to 0.
+end
+
+
+define mod-print-symbols
+    mod-validate $arg0
+    if $mod != 0
+	set $i = 0
+	while $i < $mod->nsyms
+	    set $sym = $mod->syms[$i]
+	    printf "%p\t%s\n", $sym->value, $sym->name
+	    set $i = $i + 1
+	end
+    end
+end
+document mod-print-symbols
+mod-print-symbols <module-address>
+Print all exported symbols of the module.  see mod-list
+end
+
+
+define mod-add-symbols-align
+    mod-validate $arg0
+    if $mod != 0
+	set $mod_base = ($mod->size_of_struct + (long)$mod)
+	if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0)
+	    set $mod_base = ($mod_base | ($arg2 - 1)) + 1
+	end
+	add-symbol-file $arg1 $mod_base
+    end
+end
+document mod-add-symbols-align
+mod-add-symbols-align <module-address> <object file path name> <align>
+Load the symbols table of the module from the object file where
+first section aligment is <align>.
+To retreive alignment, use `objdump -h <object file path name>'.
+end
+
+define mod-add-symbols
+    mod-add-symbols-align $arg0 $arg1 sizeof(long)
+end
+document mod-add-symbols
+mod-add-symbols <module-address> <object file path name>
+Load the symbols table of the module from the object file.
+Default alignment is 4.  See mod-add-symbols-align.
+end
+
+define mod-add-lis
+    mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16
+end
+document mod-add-lis
+mod-add-lis <module-address>
+Does mod-add-symbols <module-address> /usr/src/LiS/streams.o
+end
--- diff/Documentation/i386/kgdb/gdbinit.hw	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit.hw	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,117 @@
+
+#Using ia-32 hardware breakpoints.
+#
+#4 hardware breakpoints are available in ia-32 processors. These breakpoints
+#do not need code modification. They are set using debug registers.
+#
+#Each hardware breakpoint can be of one of the
+#three types: execution, write, access.
+#1. An Execution breakpoint is triggered when code at the breakpoint address is
+#executed.
+#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
+#at the breakpoint address is written.
+#3. An access breakpoint is triggered when memory location at the breakpoint
+#address is either read or written.
+#
+#As hardware breakpoints are available in limited number, use software
+#breakpoints ( br command in gdb ) instead of execution hardware breakpoints.
+#
+#Length of an access or a write breakpoint defines length of the datatype to
+#be watched. Length is 1 for char, 2 short , 3 int.
+#
+#For placing execution, write and access breakpoints, use commands
+#hwebrk, hwwbrk, hwabrk
+#To remove a breakpoint use hwrmbrk command.
+#
+#These commands take following types of arguments. For arguments associated
+#with each command, use help command.
+#1. breakpointno: 0 to 3
+#2. length: 1 to 3
+#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
+#
+#Use the command exinfo to find which hardware breakpoint occured.
+
+#hwebrk breakpointno address
+define hwebrk
+	maintenance packet Y$arg0,0,0,$arg1
+end
+document hwebrk
+	hwebrk <breakpointno> <address>
+	Places a hardware execution breakpoint
+	<breakpointno> = 0 - 3
+	<address> = Hex digits without leading "0x".
+end
+
+#hwwbrk breakpointno length address
+define hwwbrk
+	maintenance packet Y$arg0,1,$arg1,$arg2
+end
+document hwwbrk
+	hwwbrk <breakpointno> <length> <address>
+	Places a hardware write breakpoint
+	<breakpointno> = 0 - 3
+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
+	<address> = Hex digits without leading "0x".
+end
+
+#hwabrk breakpointno length address
+define hwabrk
+	maintenance packet Y$arg0,1,$arg1,$arg2
+end
+document hwabrk
+	hwabrk <breakpointno> <length> <address>
+	Places a hardware access breakpoint
+	<breakpointno> = 0 - 3
+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
+	<address> = Hex digits without leading "0x".
+end
+
+#hwrmbrk breakpointno
+define hwrmbrk
+	maintenance packet y$arg0
+end
+document hwrmbrk
+	hwrmbrk <breakpointno>
+	<breakpointno> = 0 - 3
+	Removes a hardware breakpoint
+end
+
+define reboot
+        maintenance packet r
+end
+#exinfo
+define exinfo
+	maintenance packet qE
+end
+document exinfo
+	exinfo
+	Gives information about a breakpoint.
+end
+define get_th
+	p $th=(struct thread_info *)((int)$esp & ~8191)
+end
+document get_th
+	get_tu
+	Gets and prints the current thread_info pointer, Defines th to be it.
+end
+define get_cu
+	p $cu=((struct thread_info *)((int)$esp & ~8191))->task
+end
+document get_cu
+	get_cu
+	Gets and print the "current" value.  Defines $cu to be it.
+end
+define int_off
+	set var $flags=$eflags
+	set $eflags=$eflags&~0x200
+	end
+define int_on
+	set var $eflags|=$flags&0x200
+	end
+document int_off
+	saves the current interrupt state and clears the processor interrupt
+	flag.  Use int_on to restore the saved flag.
+end
+document int_on
+	Restores the interrupt flag saved by int_off.
+end
--- diff/Documentation/i386/kgdb/kgdb.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/kgdb.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,775 @@
+Last edit: <20030806.1637.12>
+This file has information specific to the i386 kgdb option.  Other
+platforms with the kgdb option may behave in a similar fashion.
+
+New features:
+============
+20030806.1557.37
+This version was made against the 2.6.0-test2 kernel. We have made the
+following changes:
+
+- The getthread() code in the stub calls find_task_by_pid().  It fails
+  if we are early in the bring up such that the pid arrays have yet to
+  be allocated.  We have added a line to kernel/pid.c to make
+  "kgdb_pid_init_done" true once the arrays are allocated.  This way the
+  getthread() code knows not to call.  This is only used by the thread
+  debugging stuff and threads will not yet exist at this point in the
+  boot.
+
+- For some reason, gdb was not asking for a new thread list when the
+  "info thread" command was given.  We changed to the newer version of
+  the thread info command and gdb now seems to ask when needed.  Result,
+  we now get all threads in the thread list.
+
+- We now respond to the ThreadExtraInfo request from gdb with the thread
+  name from task_struct .comm.  This then appears in the thread list.
+  Thoughts on additional options for this are welcome.  Things such as
+  "has BKL" and "Preempted" come to mind.  I think we could have a flag
+  word that could enable different bits of info here.
+
+- We now honor, sort of, the C and S commands.  These are continue and
+  single set after delivering a signal.  We ignore the signal and do the
+  requested action.  This only happens when we told gdb that a signal
+  was the reason for entry, which is only done on memory faults.  The
+  result is that you can now continue into the Oops.
+
+- We changed the -g to -gdwarf-2.  This seems to be the same as -ggdb,
+  but it is more exact on what language to use.
+
+- We added two dwarf2 include files and a bit of code at the end of
+  entry.S.  This does not yet work, so it is disabled.  Still we want to
+  keep track of the code and "maybe" someone out there can fix it.
+
+- Randy Dunlap sent some fix ups for this file which are now merged.
+
+- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a
+  compiler warning if CONFIG_KGDB is off (now who would do that :).
+
+- Andrew Morton sent a fix for the serial driver which is now merged.
+
+- Andrew also sent a change to the stub around the cpu managment code
+  which is also merged.
+
+- Andrew also sent a patch to make "f" as well as "g" work as SysRq
+  commands to enter kgdb, merged.
+
+- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a
+  "who" field to the spinlock data struct.  This is filled with
+  "current" when ever the spinlock suceeds.  Useful if you want to know
+  who has the lock.
+
+_ And last, but not least, we fixed the "get_cu" macro to properly get
+  the current value of "current".
+
+New features:
+============
+20030505.1827.27
+We are starting to align with the sourceforge version, at least in
+commands.  To this end, the boot command string to start kgdb at
+boot time has been changed from "kgdb" to "gdb".
+
+Andrew Morton sent a couple of patches which are now included as follows:
+1.) We now return a flag to the interrupt handler.
+2.) We no longer use smp_num_cpus (a conflict with the lock meter).
+3.) And from William Lee Irwin III <wli@holomorphy.com> code to make
+    sure high-mem is set up before we attempt to register our interrupt
+    handler.
+We now include asm/kgdb.h from config.h so you will most likely never
+have to include it.  It also 'NULLS' the kgdb macros you might have in
+your code when CONFIG_KGDB is not defined.  This allows you to just
+turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such.
+This include is conditioned on the machine being an x86 so as to not
+mess with other archs.
+
+20020801.1129.03
+This is currently the version for the 2.4.18 (and beyond?) kernel.
+
+We have several new "features" beginning with this version:
+
+1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI.  No more
+    waiting and it will pull that guy out of an IRQ off spin lock :)
+
+2.) We doctored up the code that tells where a task is waiting and
+    included it so that the "info thread" command will show a bit more
+    than "schedule()".  Try it...
+
+3.) Added the ability to call a function from gdb.  All the standard gdb
+    issues apply, i.e. if you hit a breakpoint in the function, you are
+    not allowed to call another (gdb limitation, not kgdb).  To help
+    this capability we added a memory allocation function.  Gdb does not
+    return this memory (it is used for strings that you pass to that function
+    you are calling from gdb) so we fixed up a way to allow you to
+    manually return the memory (see below).
+
+4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the
+    interrupt flag to now also include the preemption count and the
+    "in_interrupt" info.  The flag is now called "with_pif" to indicate
+    the order, preempt_count, in_interrupt, flag.  The preempt_count is
+    shifted left by 4 bits so you can read the count in hex by dropping
+    the low order digit.  In_interrupt is in bit 1, and the flag is in
+    bit 0.
+
+5.) The command: "p kgdb_info" is now expanded and prints something
+    like:
+(gdb) p kgdb_info
+$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259,
+  errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1,
+  cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0,
+      regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}}
+
+    Things to note here: a.) used_malloc is the amount of memory that
+    has been malloc'ed to do calls from gdb.  You can reclaim this
+    memory like this: "p kgdb_info.used_malloc=0" Cool, huh?  b.)
+    cpus_waiting is now "sized" by the number of CPUs you enter at
+    configure time in the kgdb configure section.  This is NOT used
+    anywhere else in the system, but it is "nice" here.  c.)  The task's
+    "pid" is now in the structure.  This is the pid you will need to use
+    to decode to the thread id to get gdb to look at that thread.
+    Remember that the "info thread" command prints a list of threads
+    wherein it numbers each thread with its reference number followed
+    by the thread's pid.  Note that the per-CPU idle threads actually
+    have pids of 0 (yes, there is more than one pid 0 in an SMP system).
+    To avoid confusion, kgdb numbers these threads with numbers beyond
+    the MAX_PID.  That is why you see 32768 and above.
+
+6.) A subtle change, we now provide the complete register set for tasks
+    that are active on the other CPUs.  This allows better trace back on
+    those tasks.
+
+    And, let's mention what we could not fix.  Back-trace from all but the
+    thread that we trapped will, most likely, have a bogus entry in it.
+    The problem is that gdb does not recognize the entry code for
+    functions that use "current" near (at all?) the entry.  The compiler
+    is putting the "current" decode as the first two instructions of the
+    function where gdb expects to find %ebp changing code.  Back trace
+    also has trouble with interrupt frames.  I am talking with Daniel
+    Jacobowitz about some way to fix this, but don't hold your breath.
+
+20011220.0050.35
+Major enhancement with this version is the ability to hold one or more
+CPUs in an SMP system while allowing the others to continue.  Also, by
+default only the current CPU is enabled on single-step commands (please
+note that gdb issues single-step commands at times other than when you
+use the si command).
+
+Another change is to collect some useful information in
+a global structure called "kgdb_info".  You should be able to just:
+
+p kgdb_info
+
+although I have seen cases where the first time this is done gdb just
+prints the first member but prints the whole structure if you then enter
+CR (carriage return or enter).  This also works:
+
+p *&kgdb_info
+
+Here is a sample:
+(gdb) p kgdb_info
+$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0,
+  vector = 3, print_debug_info = 0}
+
+"Called_from" is the return address from the current entry into kgdb.
+Sometimes it is useful to know why you are in kgdb, for example, was
+it an NMI or a real breakpoint?  The simple way to interrogate this
+return address is:
+
+l *0xc010732c
+
+which will print the surrounding few lines of source code.
+
+"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the
+kgdb_ts entries).
+
+"errcode" and "vector" are other entry parameters which may be helpful on
+some traps.
+
+"print_debug_info" is the internal debugging kgdb print enable flag.  Yes,
+you can modify it.
+
+In SMP systems kgdb_info also includes the "cpus_waiting" structure and
+"hold_on_step":
+
+(gdb) p kgdb_info
+$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0,
+  vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{
+      task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0,
+      regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}}}
+
+"Cpus_waiting" has an entry for each CPU other than the current one that
+has been stopped.  Each entry contains the task_struct address for that
+CPU, the address of the regs for that task and a hold flag.  All these
+have the proper typing so that, for example:
+
+p *kgdb_info.cpus_waiting[1].regs
+
+will print the registers for CPU 1.
+
+"Hold_on_sstep" is a new feature with this version and comes up set or
+true.  What this means is that whenever kgdb is asked to single-step all
+other CPUs are held (i.e. not allowed to execute).  The flag applies to
+all but the current CPU and, again, can be changed:
+
+p kgdb_info.hold_on_sstep=0
+
+restores the old behavior of letting all CPUs run during single-stepping.
+
+Likewise, each CPU has a "hold" flag, which if set, locks that CPU out
+of execution.  Note that this has some risk in cases where the CPUs need
+to communicate with each other.  If kgdb finds no CPU available on exit,
+it will push a message thru gdb and stay in kgdb.  Note that it is legal
+to hold the current CPU as long as at least one CPU can execute.
+
+20010621.1117.09
+This version implements an event queue.  Events are signaled by calling
+a function in the kgdb stub and may be examined from gdb.  See EVENTS
+below for details.  This version also tightens up the interrupt and SMP
+handling to not allow interrupts on the way to kgdb from a breakpoint
+trap.  It is fine to allow these interrupts for user code, but not
+system debugging.
+
+Version
+=======
+
+This version of the kgdb package was developed and tested on
+kernel version 2.4.16.  It will not install on any earlier kernels.
+It is possible that it will continue to work on later versions
+of 2.4 and then versions of 2.5 (I hope).
+
+
+Debugging Setup
+===============
+
+Designate one machine as the "development" machine.  This is the
+machine on which you run your compiles and which has your source
+code for the kernel.  Designate a second machine as the "target"
+machine.  This is the machine that will run your experimental
+kernel.
+
+The two machines will be connected together via a serial line out
+one or the other of the COM ports of the PC.  You will need the
+appropriate modem eliminator (null modem) cable(s) for this.
+
+Decide on which tty port you want the machines to communicate, then
+connect them up back-to-back using the null modem cable.  COM1 is
+/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection
+with the two machines prior to trying to debug a kernel.  Once you
+have it working, on the TARGET machine, enter:
+
+setserial /dev/ttyS0 (or what ever tty you are using)
+
+and record the port address and the IRQ number.
+
+On the DEVELOPMENT machine you need to apply the patch for the kgdb
+hooks.  You have probably already done that if you are reading this
+file.
+
+On your DEVELOPMENT machine, go to your kernel source directory and do
+"make Xconfig" where X is one of "x", "menu", or "".  If you are
+configuring in the standard serial driver, it must not be a module.
+Either yes or no is ok, but making the serial driver a module means it
+will initialize after kgdb has set up the UART interrupt code and may
+cause a failure of the control-C option discussed below.  The configure
+question for the serial driver is under the "Character devices" heading
+and is:
+
+"Standard/generic (8250/16550 and compatible UARTs) serial support"
+
+Go down to the kernel debugging menu item and open it up.  Enable the
+kernel kgdb stub code by selecting that item.  You can also choose to
+turn on the "-ggdb -O1" compile options.  The -ggdb causes the compiler
+to put more debug info (like local symbols) in the object file.  On the
+i386 -g and -ggdb are the same so this option just reduces to "O1".  The
+-O1 reduces the optimization level.  This may be helpful in some cases,
+be aware, however, that this may also mask the problem you are looking
+for.
+
+The baud rate.  Default is 115200.  What ever you choose be sure that
+the host machine is set to the same speed.  I recommend the default.
+
+The port.  This is the I/O address of the serial UART that you should
+have gotten using setserial as described above.  The standard COM1 port
+(3f8) using IRQ 4 is default.  COM2 is 2f8 which by convention uses IRQ
+3.
+
+The port IRQ (see above).
+
+Stack overflow test.  This option makes a minor change in the trap,
+system call and interrupt code to detect stack overflow and transfer
+control to kgdb if it happens.  (Some platforms have this in the
+baseline code, but the i386 does not.)
+
+You can also configure the system to recognize the boot option
+"console=kgdb" which if given will cause all console output during
+booting to be put thru gdb as well as other consoles.  This option
+requires that gdb and kgdb be connected prior to sending console output
+so, if they are not, a breakpoint is executed to force the connection.
+This will happen before any kernel output (it is going thru gdb, right),
+and will stall the boot until the connection is made.
+
+You can also configure in a patch to SysRq to enable the kGdb SysRq.
+This request generates a breakpoint.  Since the serial port IRQ line is
+set up after any serial drivers, it is possible that this command will
+work when the control-C will not.
+
+Save and exit the Xconfig program.  Then do "make clean" , "make dep"
+and "make bzImage" (or whatever target you want to make).  This gets the
+kernel compiled with the "-g" option set -- necessary for debugging.
+
+You have just built the kernel on your DEVELOPMENT machine that you
+intend to run on your TARGET machine.
+
+To install this new kernel, use the following installation procedure.
+Remember, you are on the DEVELOPMENT machine patching the kernel source
+for the kernel that you intend to run on the TARGET machine.
+
+Copy this kernel to your target machine using your usual procedures.  I
+usually arrange to copy development:
+/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine
+via a LAN based NFS access.  That is, I run the cp command on the target
+and copy from the development machine via the LAN.  Run Lilo (see "man
+lilo" for details on how to set this up) on the new kernel on the target
+machine so that it will boot!  Then boot the kernel on the target
+machine.
+
+On the DEVELOPMENT machine, create a file called .gdbinit in the
+directory /usr/src/linux.  An example .gdbinit file looks like this:
+
+shell echo -e "\003" >/dev/ttyS0
+set remotebaud 38400 (or what ever speed you have chosen)
+target remote /dev/ttyS0
+
+
+Change the "echo" and "target" definition so that it specifies the tty
+port that you intend to use.  Change the "remotebaud" definition to
+match the data rate that you are going to use for the com line.
+
+You are now ready to try it out.
+
+Boot your target machine with "kgdb" in the boot command i.e. something
+like:
+
+lilo> test kgdb
+
+or if you also want console output thru gdb:
+
+lilo> test kgdb console=kgdb
+
+You should see the lilo message saying it has loaded the kernel and then
+all output stops.  The kgdb stub is trying to connect with gdb.  Start
+gdb something like this:
+
+
+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
+When gdb gets the symbols loaded it will read your .gdbinit file and, if
+everything is working correctly, you should see gdb print out a few
+lines indicating that a breakpoint has been taken.  It will actually
+show a line of code in the target kernel inside the kgdb activation
+code.
+
+The gdb interaction should look something like this:
+
+    linux-dev:/usr/src/linux# gdb vmlinux
+    GDB is free software and you are welcome to distribute copies of it
+     under certain conditions; type "show copying" to see the conditions.
+    There is absolutely no warranty for GDB; type "show warranty" for details.
+    GDB 4.15.1 (i486-slackware-linux),
+    Copyright 1995 Free Software Foundation, Inc...
+    breakpoint () at i386-stub.c:750
+    750     }
+    (gdb)
+
+You can now use whatever gdb commands you like to set breakpoints.
+Enter "continue" to start your target machine executing again.  At this
+point the target system will run at full speed until it encounters
+your breakpoint or gets a segment violation in the kernel, or whatever.
+
+If you have the kgdb console enabled when you continue, gdb will print
+out all the console messages.
+
+The above example caused a breakpoint relatively early in the boot
+process.  For the i386 kgdb it is possible to code a break instruction
+as the first C-language point in init/main.c, i.e. as the first instruction
+in start_kernel().  This could be done as follows:
+
+#include <asm/kgdb.h>
+	 breakpoint();
+
+This breakpoint() is really a function that sets up the breakpoint and
+single-step hardware trap cells and then executes a breakpoint.  Any
+early hard coded breakpoint will need to use this function.  Once the
+trap cells are set up they need not be set again, but doing it again
+does not hurt anything, so you don't need to be concerned about which
+breakpoint is hit first.  Once the trap cells are set up (and the kernel
+sets them up in due course even if breakpoint() is never called) the
+macro:
+
+BREAKPOINT;
+
+will generate an inline breakpoint.  This may be more useful as it stops
+the processor at the instruction instead of in a function a step removed
+from the location of interest.  In either case <asm/kgdb.h> must be
+included to define both breakpoint() and BREAKPOINT.
+
+Triggering kgdbstub at other times
+==================================
+
+Often you don't need to enter the debugger until much later in the boot
+or even after the machine has been running for some time.  Once the
+kernel is booted and interrupts are on, you can force the system to
+enter the debugger by sending a control-C to the debug port. This is
+what the first line of the recommended .gdbinit file does.  This allows
+you to start gdb any time after the system is up as well as when the
+system is already at a breakpoint.  (In the case where the system is
+already at a breakpoint the control-C is not needed, however, it will
+be ignored by the target so no harm is done.  Also note the the echo
+command assumes that the port speed is already set.  This will be true
+once gdb has connected, but it is best to set the port speed before you
+run gdb.)
+
+Another simple way to do this is to put the following file in you ~/bin
+directory:
+
+#!/bin/bash
+echo  -e "\003"  > /dev/ttyS0
+
+Here, the ttyS0 should be replaced with what ever port you are using.
+The "\003" is control-C.  Once you are connected with gdb, you can enter
+control-C at the command prompt.
+
+An alternative way to get control to the debugger is to enable the kGdb
+SysRq command.  Then you would enter Alt-SysRq-g (all three keys at the
+same time, but push them down in the order given).  To refresh your
+memory of the available SysRq commands try Alt-SysRq-=.  Actually any
+undefined command could replace the "=", but I like to KNOW that what I
+am pushing will never be defined.
+
+Debugging hints
+===============
+
+You can break into the target machine at any time from the development
+machine by typing ^C (see above paragraph).  If the target machine has
+interrupts enabled this will stop it in the kernel and enter the
+debugger.
+
+There is unfortunately no way of breaking into the kernel if it is
+in a loop with interrupts disabled, so if this happens to you then
+you need to place exploratory breakpoints or printk's into the kernel
+to find out where it is looping.  The exploratory breakpoints can be
+entered either thru gdb or hard coded into the source.  This is very
+handy if you do something like:
+
+if (<it hurts>) BREAKPOINT;
+
+
+There is a copy of an e-mail in the Documentation/i386/kgdb/ directory
+(debug-nmi.txt) which describes how to create an NMI on an ISA bus
+machine using a paper clip.  I have a sophisticated version of this made
+by wiring a push button switch into a PC104/ISA bus adapter card.  The
+adapter card nicely furnishes wire wrap pins for all the ISA bus
+signals.
+
+When you are done debugging the kernel on the target machine it is a
+good idea to leave it in a running state.  This makes reboots faster,
+bypassing the fsck.  So do a gdb "continue" as the last gdb command if
+this is possible.  To terminate gdb itself on the development machine
+and leave the target machine running, first clear all breakpoints and
+continue, then type ^Z to suspend gdb and then kill it with "kill %1" or
+something similar.
+
+If gdbstub Does Not Work
+========================
+
+If it doesn't work, you will have to troubleshoot it.  Do the easy
+things first like double checking your cabling and data rates.  You
+might try some non-kernel based programs to see if the back-to-back
+connection works properly.  Just something simple like cat /etc/hosts
+>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you
+if you can send data from one machine to the other.  Make sure it works
+in both directions.  There is no point in tearing out your hair in the
+kernel if the line doesn't work.
+
+All of the real action takes place in the file
+/usr/src/linux/arch/i386/kernel/kgdb_stub.c.  That is the code on the target
+machine that interacts with gdb on the development machine.  In gdb you can
+turn on a debug switch with the following command:
+
+	set remotedebug
+
+This will print out the protocol messages that gdb is exchanging with
+the target machine.
+
+Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is
+the code that talks to the serial port on the target side.  There might
+be a problem there.  In particular there is a section of this code that
+tests the UART which will tell you what UART you have if you define
+"PRNT" (just remove "_off" from the #define PRNT_off).  To view this
+report you will need to boot the system without any beakpoints.  This
+allows the kernel to run to the point where it calls kgdb to set up
+interrupts.  At this time kgdb will test the UART and print out the type
+it finds.  (You need to wait so that the printks are actually being
+printed.  Early in the boot they are cached, waiting for the console to
+be enabled.  Also, if kgdb is entered thru a breakpoint it is possible
+to cause a dead lock by calling printk when the console is locked.  The
+stub thus avoids doing printks from breakpoints, especially in the
+serial code.)  At this time, if the UART fails to do the expected thing,
+kgdb will print out (using printk) information on what failed.  (These
+messages will be buried in all the other boot up messages.  Look for
+lines that start with "gdb_hook_interrupt:".  You may want to use dmesg
+once the system is up to view the log.  If this fails or if you still
+don't connect, review your answers for the port address.  Use:
+
+setserial /dev/ttyS0
+
+to get the current port and IRQ information.  This command will also
+tell you what the system found for the UART type. The stub recognizes
+the following UART types:
+
+16450, 16550, and 16550A
+
+If you are really desperate you can use printk debugging in the
+kgdbstub code in the target kernel until you get it working.  In particular,
+there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c
+named "remote_debug".  Compile your kernel with this set to 1, rather
+than 0 and the debug stub will print out lots of stuff as it does
+what it does.  Likewise there are debug printks in the kgdb_serial.c
+code that can be turned on with simple changes in the macro defines.
+
+
+Debugging Loadable Modules
+==========================
+
+This technique comes courtesy of Edouard Parmelan
+<Edouard.Parmelan@quadratec.fr>
+
+When you run gdb, enter the command
+
+source gdbinit-modules
+
+This will read in a file of gdb macros that was installed in your
+kernel source directory when kgdb was installed.  This file implements
+the following commands:
+
+mod-list
+    Lists the loaded modules in the form <module-address> <module-name>
+
+mod-print-symbols <module-address>
+    Prints all the symbols in the indicated module.
+
+mod-add-symbols <module-address> <object-file-path-name>
+    Loads the symbols from the object file and associates them
+    with the indicated module.
+
+After you have loaded the module that you want to debug, use the command
+mod-list to find the <module-address> of your module.  Then use that
+address in the mod-add-symbols command to load your module's symbols.
+From that point onward you can debug your module as if it were a part
+of the kernel.
+
+The file gdbinit-modules also contains a command named mod-add-lis as
+an example of how to construct a command of your own to load your
+favorite module.  The idea is to "can" the pathname of the module
+in the command so you don't have to type so much.
+
+Threads
+=======
+
+Each process in a target machine is seen as a gdb thread. gdb thread
+related commands (info threads, thread n) can be used.
+
+ia-32 hardware breakpoints
+==========================
+
+kgdb stub contains support for hardware breakpoints using debugging features
+of ia-32(x86) processors. These breakpoints do not need code modification.
+They use debugging registers. 4 hardware breakpoints are available in ia-32
+processors.
+
+Each hardware breakpoint can be of one of the following three types.
+
+1. Execution breakpoint - An Execution breakpoint is triggered when code
+	at the breakpoint address is executed.
+
+	As limited number of hardware breakpoints are available, it is
+	advisable to use software breakpoints ( break command ) instead
+	of execution hardware breakpoints, unless modification of code
+	is to be avoided.
+
+2. Write breakpoint - A write breakpoint is triggered when memory
+	location at the breakpoint address is written.
+
+	A write or can be placed for data of variable length. Length of
+	a write breakpoint indicates length of the datatype to be
+	watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for
+	4 byte data.
+
+3. Access breakpoint - An access breakpoint is triggered when memory
+	location at the breakpoint address is either read or written.
+
+	Access breakpoints also have lengths similar to write breakpoints.
+
+IO breakpoints in ia-32 are not supported.
+
+Since gdb stub at present does not use the protocol used by gdb for hardware
+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
+for hardware breakpoints are described below.
+
+hwebrk	- Places an execution breakpoint
+	hwebrk breakpointno address
+hwwbrk	- Places a write breakpoint
+	hwwbrk breakpointno length address
+hwabrk	- Places an access breakpoint
+	hwabrk breakpointno length address
+hwrmbrk	- Removes a breakpoint
+	hwrmbrk breakpointno
+exinfo	- Tells whether a software or hardware breakpoint has occurred.
+	Prints number of the hardware breakpoint if a hardware breakpoint has
+	occurred.
+
+Arguments required by these commands are as follows
+breakpointno	- 0 to 3
+length		- 1 to 3
+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
+
+SMP support
+==========
+
+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb
+client, all the processors are forced to enter the debugger. Current
+thread corresponds to the thread running on the processor where
+breakpoint occurred.  Threads running on other processor(s) appear
+similar to other non-running threads in the 'info threads' output.
+Within the kgdb stub there is a structure "waiting_cpus" in which kgdb
+records the values of "current" and "regs" for each CPU other than the
+one that hit the breakpoint.  "current" is a pointer to the task
+structure for the task that CPU is running, while "regs" points to the
+saved registers for the task.  This structure can be examined with the
+gdb "p" command.
+
+ia-32 hardware debugging registers on all processors are set to same
+values.  Hence any hardware breakpoints may occur on any processor.
+
+gdb troubleshooting
+===================
+
+1. gdb hangs
+Kill it. restart gdb. Connect to target machine.
+
+2. gdb cannot connect to target machine (after killing a gdb and
+restarting another) If the target machine was not inside debugger when
+you killed gdb, gdb cannot connect because the target machine won't
+respond.  In this case echo "Ctrl+C"(ASCII 3) to the serial line.
+e.g. echo -e "\003" > /dev/ttyS1
+This forces that target machine into the debugger, after which you
+can connect.
+
+3. gdb cannot connect even after echoing Ctrl+C into serial line
+Try changing serial line settings min to 1 and time to 0
+e.g. stty min 1 time 0 < /dev/ttyS1
+Try echoing again
+
+Check serial line speed and set it to correct value if required
+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
+
+EVENTS
+======
+
+Ever want to know the order of things happening?  Which CPU did what and
+when?  How did the spinlock get the way it is?  Then events are for
+you.  Events are defined by calls to an event collection interface and
+saved for later examination.  In this case, kgdb events are saved by a
+very fast bit of code in kgdb which is fully SMP and interrupt protected
+and they are examined by using gdb to display them.  Kgdb keeps only
+the last N events, where N must be a power of two and is defined at
+configure time.
+
+
+Events are signaled to kgdb by calling:
+
+kgdb_ts(data0,data1)
+
+For each call kgdb records each call in an array along with other info.
+Here is the array definition:
+
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int	on_cpu;
+#endif
+	long long at_time;
+	int  	from_ln;
+	char	* in_src;
+	void	*from;
+        int     with_if;
+	int	data0;
+	int	data1;
+};
+
+For SMP machines the CPU is recorded, for all machines the TSC is
+recorded (gets a time stamp) as well as the line number and source file
+the call was made from.  The address of the (from), the "if" (interrupt
+flag) and the two data items are also recorded.  The macro kgdb_ts casts
+the types to int, so you can put any 32-bit values here.  There is a
+configure option to select the number of events you want to keep.  A
+nice number might be 128, but you can keep up to 1024 if you want.  The
+number must be a power of two.  An "andthen" macro library is provided
+for gdb to help you look at these events.  It is also possible to define
+a different structure for the event storage and cast the data to this
+structure.  For example the following structure is defined in kgdb:
+
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int	on_cpu;
+#endif
+	long long at_time;
+	int  	from_ln;
+	char	* in_src;
+	void	*from;
+        int     with_if;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+
+If you use this for display, the data elements will be displayed as
+pointers to task_struct entries.  You may want to define your own
+structure to use in casting.  You should only change the last two items
+and you must keep the structure size the same.  Kgdb will handle these
+as 32-bit ints, but within that constraint you can define a structure to
+cast to any 32-bit quantity.  This need only be available to gdb and is
+only used for casting in the display code.
+
+Final Items
+===========
+
+I picked up this code from Amit S. Kale and enhanced it.
+
+If you make some really cool modification to this stuff, or if you
+fix a bug, please let me know.
+
+George Anzinger
+<george@mvista.com>
+
+Amit S. Kale
+<akale@veritas.com>
+
+(First kgdb by David Grothe <dave@gcom.com>)
+
+(modified by Tigran Aivazian <tigran@sco.com>)
+    Putting gdbstub into the kernel config menu.
+
+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
+    Hooks for entering gdbstub at boot time.
+
+(modified by Amit S. Kale <akale@veritas.com>)
+    Threads, ia-32 hw debugging, mp support, console support,
+    nmi watchdog handling.
+
+(modified by George Anzinger <george@mvista.com>)
+    Extended threads to include the idle threads.
+    Enhancements to allow breakpoint() at first C code.
+    Use of module_init() and __setup() to automate the configure.
+    Enhanced the cpu "collection" code to work in early bring-up.
+    Added ability to call functions from gdb
+    Print info thread stuff without going back to schedule()
+    Now collect the "other" cpus with an IPI/ NMI.
--- diff/Documentation/i386/kgdb/kgdbeth.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/kgdbeth.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,92 @@
+KGDB over ethernet
+==================
+
+Authors
+-------
+
+Robert Walsh <rjwalsh@durables.org>  (2.6 port)
+wangdi <wangdi@clusterfs.com>        (2.6 port)
+Matt Mackall <mpm@selenic.com>       (netpoll api)
+San Mehat                            (original 2.4 code)
+
+
+Introduction
+------------
+
+KGDB supports debugging over ethernet (kgdboe) via polling of a given
+network interface. Most cards should be supported automatically.
+Debugging facilities are available as soon as the network driver and
+kgdboe have initialized. Unfortunately, this is too late in the boot
+process for debugging some issues, but works quite well for many
+others. This should not interfere with normal network usage and
+doesn't require a dedicated NIC.
+
+Terminology
+-----------
+
+This document uses the following terms:
+
+  TARGET: the machine being debugged.
+  HOST:   the machine running gdb.
+
+
+Usage
+-----
+
+You need to use the following command-line option on the TARGET kernel:
+
+  kgdboe=[tgt-port]@<tgt-ip>/[dev],[host-port]@<host-ip>/[host-macaddr]
+
+    where
+        tgt-port      source for UDP packets (defaults to 6443)
+        tgt-ip        source IP to use (interface address)
+        dev           network interface (eth0)
+        host-port     HOST UDP port (6442) (not really used)
+        host-ip       IP address for HOST machine
+        host-macaddr  ethernet MAC address for HOST (ff:ff:ff:ff:ff:ff)
+
+  examples:
+
+    kgdboe=7000@192.168.0.1/eth1,7001@192.168.0.2/00:05:3C:04:47:5D
+        this machine is 192.168.0.1 on eth1
+        remote machine is 192.168.0.2 with MAC address 00:05:3C:04:47:5D
+        listen for gdb packets on port 7000
+        send unsolicited gdb packets to port 7001
+
+    kgdboe=@192.168.0.1/,@192.168.0.2/
+        this machine is 192.168.0.1 on default interface eth0
+        remote machine is 192.168.0.2, use default broadcast MAC address
+        listen for gdb packets on default port 6443
+        send unsolicited gdb packets to port 6442
+
+Only packets originating from the configured HOST IP address will be
+accepted by the debugger.
+
+On the HOST side, run gdb as normal and use a remote UDP host as the
+target:
+
+   % gdb ./vmlinux
+   GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
+   Copyright 2003 Free Software Foundation, Inc.
+   GDB is free software, covered by the GNU General Public License, and you are
+   welcome to change it and/or distribute copies of it under certain conditions.
+   Type "show copying" to see the conditions.
+   There is absolutely no warranty for GDB.  Type "show warranty" for details.
+   This GDB was configured as "i386-redhat-linux-gnu"...
+   (gdb) target remote udp:HOSTNAME:6443
+
+You can now continue as if you were debugging over a serial line.
+
+Limitations
+-----------
+
+The current release of this code is exclusive of using kgdb on a
+serial interface, so you must boot without the kgdboe option to use
+serial debugging. Trying to debug the network driver while using it
+will prove interesting.
+
+Bug reports
+-----------
+
+Send bug reports to Robert Walsh <rjwalsh@durables.org> and Matt
+Mackall <mpm@selenic.com>.
--- diff/Documentation/i386/kgdb/loadmodule.sh	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/loadmodule.sh	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,78 @@
+#/bin/sh
+# This script loads a module on a target machine and generates a gdb script.
+# source generated gdb script to load the module file at appropriate addresses
+# in gdb.
+#
+# Usage:
+# Loading the module on target machine and generating gdb script)
+#	[foo]$ loadmodule.sh <modulename>
+#
+# Loading the module file into gdb
+#	(gdb) source <gdbscriptpath>
+#
+# Modify following variables according to your setup.
+#	TESTMACHINE - Name of the target machine
+#	GDBSCRIPTS - The directory where a gdb script will be generated
+#
+# Author: Amit S. Kale (akale@veritas.com).
+#
+# If you run into problems, please check files pointed to by following
+# variables.
+#	ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
+#	MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
+#	GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
+
+TESTMACHINE=foo
+GDBSCRIPTS=/home/bar
+
+if [ $# -lt 1 ] ; then {
+	echo Usage: $0 modulefile
+	exit
+} ; fi
+
+MODULEFILE=$1
+MODULEFILEBASENAME=`basename $1`
+
+if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
+	MODULEFILE=`pwd`/$MODULEFILE
+} fi
+
+ERRFILE=/tmp/$MODULEFILEBASENAME.errs
+MAPFILE=/tmp/$MODULEFILEBASENAME.map
+GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
+
+function findaddr() {
+	local ADDR=0x$(echo "$SEGMENTS" | \
+		grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
+		sed 's/[ ]*[^ ]*$//')
+	echo $ADDR
+}
+
+function checkerrs() {
+	if [ "`cat $ERRFILE`" != "" ] ; then {
+		cat $ERRFILE
+		exit
+	} fi
+}
+
+#load the module
+echo Copying $MODULEFILE to $TESTMACHINE
+rcp $MODULEFILE root@${TESTMACHINE}:
+
+echo Loading module $MODULEFILE
+rsh -l root $TESTMACHINE  /sbin/insmod -m ./`basename $MODULEFILE` \
+	> $MAPFILE 2> $ERRFILE
+checkerrs
+
+SEGMENTS=`head -n 11 $MAPFILE | tail -n 10`
+TEXTADDR=$(findaddr "\\.text[^.]")
+LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
+SEGADDRS=`echo "$SEGMENTS" | awk '//{
+	if ($1 != ".text" && $1 != ".this" &&
+	    $1 != ".kstrtab" && $1 != ".kmodtab") {
+		print " -s " $1 " 0x" $3 " "
+	}
+}'`
+LOADSTRING="$LOADSTRING $SEGADDRS"
+echo Generating script $GDBSCRIPT
+echo $LOADSTRING > $GDBSCRIPT
--- diff/Documentation/ia64/kgdb.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/ia64/kgdb.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,9 @@
+IA64 kgdb requires a patch to gdb/remote.c. The proposed patch will eventually be in gdb but
+until then, within gdb do "show remote" and look for "Support for remote protocol `p' (fetch-register) packet is auto-detected, currently unknown."  Should this line not appear, then you must
+obtain the patch, apply it and build gdb.
+
+CONFIG_KGDB_EARLY enables one with serial kgdb support to debug the kernel starting at the
+end of the routine setup_arch.  A boot option of "kgdb=1" will result in a kernel breakpoint
+and requires gdb to continue from the breakpoint.
+
+For further information consult the i386 kgdb documentation.
--- diff/Documentation/must-fix.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/must-fix.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,288 @@
+
+Must-fix bugs
+=============
+
+drivers/char/
+~~~~~~~~~~~~~
+
+o TTY locking is broken.
+
+  o see FIXME in do_tty_hangup().  This causes ppp BUGs in local_bh_enable()
+
+  o Other problems: aviro, dipankar, Alan have details.
+
+  o somebody will have to document the tty driver and ldisc API
+
+drivers/tty
+~~~~~~~~~~~
+
+o viro: tty_driver refcounting, tty/misc/upper levels of sound still not
+  completely fixed.
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o loop.c: Concurrent write access on block devices might cause a deadlock
+  of the complete system. See:
+  http://marc.theaimsgroup.com/?l=linux-kernel&m=106275365925769&w==
+  http://bugzilla.kernel.org/show_bug.cgi?id=1198
+  Thread of possible fix:
+  http://www.kerneli.org/pipermail/cryptoapi-devel/2003-October/000676.html
+
+  (Fruhwirth Clemens)
+
+o ideraid hasn't been ported to 2.5 at all yet.
+
+  We need to understand whether the proposed BIO split code will suffice
+  for this.
+
+drivers/input/
+~~~~~~~~~~~~~~
+
+o rmk: unconverted keyboard/mouse drivers (there's a deadline of 2.6.0
+  currently on these remaining in my/Linus' tree.)
+
+o viro: large absence of locking.
+
+o viro: parport is nearly as bad as that and there the code is more hairy.
+  IMO parport is more of "figure out what API changes are needed for its
+  users, get them done ASAP, then fix generic layer at leisure"
+
+o (Albert Cahalan) Lots of people (check Google) get this message from the
+  kernel:
+
+  psmouse.c: Lost synchronization, throwing 2 bytes away.
+
+  (the number of bytes will be 1, 2, or 3)
+
+  At work, I get it when there is heavy NFS traffic.  The mouse goes crazy,
+  jumping around and doing random cut-and-paste all over everything.  This
+  is with a decently fast and modern PC.
+
+o There seem to be too many reports of keyboards and mice failing or acting
+  strangely.
+
+
+drivers/misc/
+~~~~~~~~~~~~~
+
+o rmk: UCB1[23]00 drivers, currently sitting in drivers/misc in the ARM
+  tree.  (touchscreen, audio, gpio, type device.)
+
+  These need to be moved out of drivers/misc/ and into real places
+
+o viro: actually, misc.c has a good chance to die.  With cdev-cidr that's
+  trivial.
+
+drivers/net/
+~~~~~~~~~~~~
+
+drivers/net/irda/
+~~~~~~~~~~~~~~~~~
+
+  (Jean Tourrilhes)
+
+o irport need to be converted to sir-kthread
+
+o dongle drivers need to be converted to sir-dev (in progress)
+
+o new drivers (irtty-sir/smsc-ircc2/donauboe) need more testing (in progress)
+
+
+drivers/pci/
+~~~~~~~~~~~~
+
+o alan: Some cardbus crashes the system
+
+  (bugzilla, please?)
+
+drivers/pcmcia/
+~~~~~~~~~~~~~~~
+
+o alan: This is a locking disaster.
+
+  (rmk, brodo: in progress)
+
+drivers/pld/
+~~~~~~~~~~~~
+
+o rmk: EPXA (ARM platform) PLD hotswap drivers (drivers/pld)
+
+  (rmk: will work out what to do here.  maybe drivers/arm/)
+
+drivers/video/
+~~~~~~~~~~~~~~
+
+o Lots of drivers don't compile, others do but don't work.
+
+drivers/scsi/
+~~~~~~~~~~~~~
+
+o Convert am53c974, dpt_i2o, initio and pci2220i to DMA-mapping
+
+o Make inia100, cpqfc, pci2000 and dc390t compile
+
+o Convert
+
+   wd33c99 based: a2091 a3000 gpv11 mvme174 sgiwd93
+
+   53c7xx based: amiga7xxx bvme6000 mvme16x initio am53c974 pci2000
+   pci2220i dc390t
+
+  To new error handling
+
+  It also might be possible to shift the 53c7xx based drivers over to
+  53c700 which does the new EH stuff, but I don't have the hardware to check
+  such a shift.
+
+  For the non-compiling stuff, I've probably missed a few that just aren't
+  compilable on my platforms, so any updates would be welcome.  Also, are
+  some of our non-compiling or unconverted drivers obsolete?
+
+fs/
+~~~
+
+o AIO/direct-IO writes can race with truncate and wreck filesystems.
+  (Badari has a patch)
+
+o viro: fs/char_dev.c needs removal of aeb stuff and merge of cdev-cidr.
+  In progress.
+
+o forward-port sct's O_DIRECT fixes (Badari has a patch)
+
+o viro: there is some generic stuff for namei/namespace/super, but that's a
+  slow-merge and can go in 2.6 just fine
+
+o trond: NFS has a mmap-versus-truncate problem (fixed? needs testing)
+
+o trond: NFSv4 client, bugs in lockd, RPSEC_GSS for NFSv[23], some atomic open
+  bits. more info: http://www.fys.uio.no/~trondmy/src/Linux-2.6.x/2.6.0-test11/
+
+kernel/sched.c
+~~~~~~~~~~~~~~
+
+o Starvation, general interactivity need close monitoring.
+
+o SMT aware scheduler (Ingo, Rusty, Nick have implementations)
+
+kernel/
+~~~~~~~
+
+o Alan: 32bit uid support is *still* broken for process accounting.
+
+  Create a 32bit uid, turn accounting on.  Shock horror it doesn't work
+  because the field is 16bit.  We need an acct structure flag day for 2.6
+  IMHO
+
+  (alan has patch)
+
+o viro: core sysctl code is racy.  And its interaction wiuth sysfs
+
+o (ingo) rwsems (on x86) are limited to 32766 waiting processes.  This
+  means that setting pid_max to above 32K is unsafe :-(
+
+  An option is to use CONFIG_RWSEM_GENERIC_SPINLOCK variant all the time,
+  for all archs, and not inline any part of the ops.
+
+lib/kobject.c
+~~~~~~~~~~~~~
+
+o kobject refcounting (comments from Al Viro):
+
+  _anything_ can grab a temporary reference to kobject.  IOW, if kobject is
+  embedded into something that could be freed - it _MUST_ have a destructor
+  and that destructor _MUST_ be the destructor for containing object.
+
+  Any violation of the above (and we already have a bunch of those) is a
+  user-triggerable memory corruption.
+
+  We can tolerate it for a while in 2.5 (e.g.  during work on susbsystem we
+  can decide to switch to that way of handling objects and have subsystem
+  vulnerable for a while), but all such windows must be closed before 2.6
+  and during 2.6 we can't open them at all.
+
+o All block drivers which control multiple gendisks with a single
+  request_queue are broken, due to one-to-one assumptions in the request
+  queue sysfs hookup.
+
+mm/
+~~~
+
+o GFP_DMA32 (or something like that).  Lots of ideas.  jejb, zaitcev,
+  willy, arjan, wli.
+
+  Specifically, 64-bit systems need to be able to enforce 32-bit addressing
+  limits for device metadata like network cards' ring buffers and SCSI
+  command descriptors.
+
+o access_process_vm() doesn't flush right.  We probably need new flushing
+  primitives to do this (davem?)
+
+
+modules
+~~~~~~~
+
+  (Rusty)
+
+net/
+~~~~
+
+  (davem)
+
+o UDP apps can in theory deadlock, because the ip_append_data path can end
+  up sleeping while the socket lock is held.
+
+  It is OK to sleep with the socket held held, normally.  But in this case
+  the sleep happens while waiting for socket memory/space to become
+  available, if another context needs to take the socket lock to free up the
+  space we could hang.
+
+  I sent a rough patch on how to fix this to Alexey, and he is analyzing
+  the situation.  I expect a final fix from him next week or so.
+
+o Semantics for IPSEC during operations such as TCP connect suck currently.
+
+  When we first try to connect to a destination, we may need to ask the
+  IPSEC key management daemon to resolve the IPSEC routes for us.  For the
+  purposes of what the kernel needs to do, you can think of it like ARP.  We
+  can't send the packet out properly until we resolve the path.
+
+  What happens now for IPSEC is basically this:
+
+  O_NONBLOCK: returns -EAGAIN over and over until route is resolved
+
+  !O_NONBLOCK: Sleeps until route is resolved
+
+  These semantics are total crap.  The solution, which Alexey is working
+  on, is to allow incomplete routes to exist.  These "incomplete" routes
+  merely put the packet onto a "resolution queue", and once the key manager
+  does it's thing we finish the output of the packet.  This is precisely how
+  ARP works.
+
+  I don't know when Alexey will be done with this.
+
+net/*/netfilter/
+~~~~~~~~~~~~~~~~
+
+  (Rusty)
+
+sound/
+~~~~~~
+
+global
+~~~~~~
+
+o viro: 64-bit dev_t (not a mustfix for 2.6.0). 32-bit dev_t is done, 64-bit
+  means extra work on nfsd/raid/etc.
+
+o alan: Forward port 2.4 fixes
+  - Chris Wright: Security fixes including execve holes, execve vs proc races
+
+o There are about 60 or 70 security related checks that need doing
+  (copy_user etc) from Stanford tools.  (badari is looking into this, and
+  hollisb)
+
+o A couple of hundred real looking bugzilla bugs
+
+o viro: cdev rework. Mostly done.
+
--- diff/Documentation/should-fix.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/should-fix.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,541 @@
+Not-ready features and speedups
+===============================
+
+Legend:
+
+PRI1:	We're totally lame if this doesn't get in
+PRI2:	Would be nice
+PRI3:	Not very important
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o viro: paride drivers need a big cleanup. Partially done, but ATAPI drivers
+  need serious work and bug fixing.
+
+  PRI2
+
+drivers/char/rtc/
+~~~~~~~~~~~~~~~~~
+
+o rmk, trini: add support for alarms to the existing generic rtc driver.
+
+  PRI2
+
+console drivers
+~~~~~~~~~~~~~~~
+  (Pavel Machek <pavel@ucw.cz>)
+
+o There are few must-fix bugs in cursor handling.
+
+o Play with gpm selection for a while and your cursor gets corrupted with
+  random dots. Ouch.
+
+device mapper
+~~~~~~~~~~~~~
+
+o ioctl interface cleanup patch is ready (redo the structure layouts)
+
+  PRI1
+
+o A port of the 2.4 snapshot and mirror targets is in progress
+
+  PRI1
+
+o the fs interface to dm needs to be redone.  gregkh was going to work on
+  this.  viro is interested in seeing work thus-far.
+
+  PRI2
+
+drivers/net/wireless/
+~~~~~~~~~~~~~~~~~~~~~
+
+  (Jean Tourrilhes <jt@bougret.hpl.hp.com>)
+
+o get HostAP driver in the kernel.  No consolidation of the 802.11
+  management across driver can happen until this one is in (which is probably
+  2.7.X material).  I think Jouni is mostly ready but didn't find time for
+  it.
+
+  PRI2
+
+o get more wireless drivers into the kernel.  The most "integrable" drivers
+  at this point seem the NWN driver, Pavel's Spectrum driver.
+
+  PRI1
+
+drivers/usb/gadget/
+~~~~~~~~~~~~~~~~~~~
+
+o rmk: SA11xx USB client/gadget code (David B has been doing some work on
+  this, and keeps trying to prod me, but unfortunately I haven't had the time
+  to look at his work, sorry David.)
+
+  PRI3
+
+fs/
+~~~
+
+o ext3 and ext2 block allocators have serious failure modes - interleaved
+  allocations.
+
+  PRI3
+
+o Integrate Chris Mason's 2.4 reiserfs ordered data and data journaling
+  patches.  They make reiserfs a lot safer.
+
+  Ordered: PRI2
+  data journalled: PRI3
+
+o viro: convert more filesystems to use lib/parser.c for options.
+
+  PRI2
+
+o aio: fs IO isn't async at present.  suparna has restart patches, they're
+  in -mm.  Need to get Ben to review/comment.
+
+  PRI1.
+
+o drepper: various filesystems use ->pid wrongly
+
+  PRI1
+
+o hch: devfs: there's a fundamental lookup vs devfsd race that's only
+  fixable by introducing a lookup vs devfs deadlock.  I can't see how this is
+  fixable without getting rid of the current devfsd design.  Mandrake seems
+  to have a workaround for this so this is at least not triggered so easily,
+  but that's not what I'd consider a fix..
+
+  PRI2
+
+kernel/
+~~~~~~~
+
+o rusty: Zippel's Reference count simplification.  Tricky code, but cuts
+  about 120 lines from module.c.  Patch exists, needs stressing.
+
+  PRI3
+
+o rusty: Fix module-failed-init races by starting module "disabled".  Patch
+  exists, requires some subsystems (ie.  add_partition) to explicitly say
+  "make module live now".  Without patch we are no worse off than 2.4 etc.
+
+  PRI1
+
+o Integrate userspace irq balancing daemon.
+
+  PRI2
+
+o kexec.  Seems to work, was in -mm.
+
+  PRI3
+
+o rmk: lib/inflate.c must not use static variables (causes these to be
+  referenced via GOTOFF relocations in PIC decompressor.  We have a PIC
+  decompressor to avoid having to hard code a per platform zImage link
+  address into the makefiles.)
+
+  PRI2
+
+o klibc merge?
+
+  PRI2
+
+mm/
+~~~
+
+o dropbehind for large files
+
+  PRI2
+
+net/
+~~~~
+
+  (davem)
+
+o Real serious use of IPSEC is hampered by lack of MPLS support.  MPLS is a
+  switching technology that works by switching based upon fixed length labels
+  prepended to packets.  Many people use this and IPSEC to implement VPNs
+  over public networks, it is also used for things like traffic engineering.
+
+  A good reference site is:
+
+	http://www.mplsrc.com/
+
+  Anyways, an existing (crappy) implementation exists.  I've almost
+  completed a rewrite, I should have something in the tree next week.
+
+  PRI1
+
+o Sometimes we generate IP fragments when it truly isn't necessary.
+
+  The way IP fragmentation is specified, each fragment must be modulo 8
+  bytes in length.  So suppose the device has an MTU that is not 0 modulo 8,
+  ethernet even classifies in this way.  1500 == (8 * 187) + 4
+
+  Our IP fragmenting engine can fragment on packets that are sized within
+  the last modulo 8 bytes of the MTU.  This happens in obscure cases, but it
+  does happen.
+
+  I've proposed a fix to Alexey, whereby very late in the output path we
+  check the packet, if we fragmented but the data length would fit into the
+  MTU we unfragment the packet.
+
+  This is low priority, because technically it creates suboptimal behavior
+  rather than mis-operation.
+
+  PRI1
+
+net/*/netfilter/
+~~~~~~~~~~~~~~~~
+
+o Lots of misc. cleanups, which are happening slowly.
+
+  PRI2
+
+power management
+~~~~~~~~~~~~~~~~
+
+o Pat and Pavel disagree over swsusp. Need to sort that out.
+
+  PRI2
+
+o Frame buffer restore codepaths (that requires some deep PCI magic)
+
+  PRI2
+
+o XFree86 hooks
+
+  PRI2
+
+o AGP restoration
+
+  PRI2
+
+o DRI restoration
+
+  (davej/Alan: not super-critical, can crash laptop on restore.  davej
+  looking into it.)
+
+  PRI2
+
+o IDE suspend/resume without races (Ben is looking at this a little)
+
+  PRI2
+
+o Pat: There are already CPU device structures; MTRRs should be a
+  dynamically registered interface of CPUs, which implies there needs
+  to be some other glue to know that there are MTRRs that need to be
+  saved/restored.
+
+  PRI1
+
+global
+~~~~~~
+
+o We need a kernel side API for reporting error events to userspace (could
+  be async to 2.6 itself)
+
+  (Prototype core based on netlink exists)
+
+  PRI2
+
+o Kai: Introduce a sane, easy and standard way to build external modules
+  - make clean and make modules_install are both broken
+
+  PRI2
+
+drivers
+~~~~~~~
+
+o Alan: Cardbus/PCMCIA requires all Russell's stuff is merged to do
+  multiheader right and so on
+
+  PRI1
+
+drivers/acpi/
+~~~~~~~~~~~~~
+
+o Fix acpi for all newer IBM Thinkpads see
+  http://bugme.osdl.org/show_bug.cgi?id=1038 for more information
+
+o alan: VIA APIC stuff is one bit of this, there are also some other
+  reports that were caused by ACPI not setting level v edge trigger some
+  times
+
+  PRI1
+
+o mochel: it seems the acpi irq routing code could use a serious rewrite.
+
+  grover: The problem is the ACPI irq routing code is trying to piggyback
+  on the existing MPS-specific data structures, and it's generally a hack.
+  So yes mochel is right, but it is also purging MPS-ities from common code
+  as well.  I've done some preliminary work in this area and it doesn't seem
+  to break anything (yet) but a rewrite in this area imho should not be
+  rushed out the door.  And, I think the above bugs can be fixed w/o the
+  rewrite.
+
+  PRI2
+
+o mochel: ACPI suspend doesn't work.  Important, not cricital.  Pat is
+  working it.
+
+  PRI2
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o More testing of floppy
+
+  PRI3
+
+drivers/char/
+~~~~~~~~~~~~~
+
+
+drivers/ide/
+~~~~~~~~~~~~
+
+  (Alan)
+
+o IDE PIO has occasional unexplained PIO disk eating reports
+
+  PRI1
+
+o IDE has multiple zillions of races/hangs in 2.5 still
+
+  PRI1
+
+o IDE scsi needs rewriting
+
+  PRI2
+
+o IDE needs significant reworking to handle Simplex right
+
+  PRI2
+
+o IDE hotplug handling for 2.5 is completely broken still
+
+  PRI2
+
+o There are lots of other IDE bugs that wont go away until the taskfile
+  stuff is included, the locking bugs that allow any user to hang the IDE
+  layer in 2.5, and some other updates are forward ported.  (esp.  HPT372N).
+
+  PRI1
+
+drivers/isdn/
+~~~~~~~~~~~~~
+
+  (Kai, rmk)
+
+o isdn_tty locking is completely broken (cli() and friends)
+
+  PRI2
+
+o fix other drivers
+
+  PRI2
+
+o lots more cleanups, adaption to recent APIs etc
+
+  PRI3
+
+o fixup tty-based ISDN drivers which provide TIOCM* ioctls (see my recent
+  3-set patch for serial stuff)
+
+  Alternatively, we could re-introduce the fallback to driver ioctl parsing
+  for these if not enough drivers get updated.
+
+  PRI3
+
+drivers/net/
+~~~~~~~~~~~~
+
+o davej: Either Wireless network drivers or PCMCIA broke somewhen.  A
+  configuration that worked fine under 2.4 doesn't receive any packets.  Need
+  to look into this more to make sure I don't have any misconfiguration that
+  just 'happened to work' under 2.4
+
+  PRI1
+
+drivers/scsi/
+~~~~~~~~~~~~~
+
+o jejb: qlogic -
+
+  o Merge the feral driver.  It covers all qlogic chips: 1020 all the way
+    up to 23xxx. http://linux-scsi.bkbits.net/scsi-isp-2.5
+
+  o qla2xxx: only for FC chips.  Has significant build issues.  hch
+    promises to send me a "must fix" list for this.
+    http://linux-scsi.bkbits.net/scsi-qla2xxx-2.5
+
+  PRI2
+
+o hch, Mike Anderson, Badari Pulavarty: scsi locking issues
+
+  o there are lots of members of struct Scsi_Host/scsi_device/scsi_cmnd
+    with very unclear locking, many of them probably want to become
+    atomic_t's or bitmaps (for the 1bit bitfields).
+
+  o there's lots of volatile abuse in the scsi code that needs to be
+    thought about.
+
+  o there's some global variables incremented without any locks
+
+  PRI2
+
+sound/
+~~~~~~
+
+o rmk: several OSS drivers for SA11xx-based hardware in need of
+  ALSA-ification and L3 bus support code for these.
+
+o rmk: need to complete ALSA-ification of the WaveArtist driver for both
+  NetWinder and other stuff (there's some fairly fundamental differences in
+  the way the mixer needs to be handled for the NetWinder.)
+
+  (Issues with forward-porting 2.4 bugfixes.)
+  (Killing off OSS is 2.7 material)
+
+PRI2
+
+arch/i386/
+~~~~~~~~~~
+
+o davej: PAT support (for mtrr exhaustion w/ AGP)
+
+  PRI2
+
+o 2.5.x won't boot on some 440GX
+
+  alan: Problem understood now, feasible fix in 2.4/2.4-ac.  (440GX has two
+  IRQ routers, we use the $PIR table with the PIIX, but the 440GX doesnt use
+  the PIIX for its IRQ routing).  Fall back to BIOS for 440GX works and Intel
+  concurs.
+
+  PRI1
+
+o 2.5.x doesn't handle VIA APIC right yet.
+
+  1. We must write the PCI_INTERRUPT_LINE
+
+  2. We have quirk handlers that seem to trash it.
+
+  PRI1
+
+o ECC driver questions are not yet sorted (DaveJ is working on this) (Dan
+  Hollis)
+
+  alan: ECC - I have some test bits from Dan's stuff - they need no kernel
+  core changes for most platforms.  That means we can treat it as a random
+  driver merge.
+
+  PRI3
+
+o alan: 2.4 has some fixes for tsc handling bugs.  One where some bioses in
+  SMM mode mess up our toggle on the time high/low or mangle the counter and
+  one where a few chips need religious use of _p for timer access and we
+  don't do that.  This is forward porting little bits of fixup.
+
+  ACPI HZ stuff we can't trap - a lot of ACPI is implemented as outb's
+  triggering SMM traps
+
+  PRI1
+
+arch/x86_64/
+~~~~~~~~~~~~
+
+  (Andi)
+
+o time handling is broken. Need to move up 2.4 time.c code.
+
+  PRI1
+
+o NMI watchdog seems to tick too fast
+
+  PRI2
+
+o need to coredump 64bit vsyscall code with dwarf2
+
+  PRI2
+
+o move 64bit signal trampolines into vsyscall code and add dwarf2 for it.
+  (in progress)
+
+  PRI1
+
+o describe kernel assembly with dwarf2 annotations for kgdb
+
+  PRI3
+
+arch/alpha/
+~~~~~~~~~~~
+
+o rth: Ptrace writes are broken.  This means we can't (reliably) set
+  breakpoints or modify variables from gdb.
+
+  PRI1
+
+arch/arm/
+~~~~~~~~~
+
+o rmk: missing raw keyboard translation tables for all ARM machines.
+  Haven't even looked into this at all.  This could be messy since there
+  isn't an ARM architecture standard.  I'm presently hoping that it won't be
+  an issue.  If it does, I guess we'll see drivers/char/keyboard.c explode.
+
+  PRI2
+
+arch/others/
+~~~~~~~~~~~~
+
+o SH needs resyncing, as do some other ports. SH64 needs merging.
+  No impact on mainstream platforms hopefully.
+
+  PRI2
+
+arch/s390/
+~~~~~~~~~
+
+o A nastly memory management problem causes random crashes.  These appear
+  to be fixed/hidden by the objrmap patch, more investigation is needed.
+
+  PRI1
+
+drivers/s390/
+~~~~~~~~~~~~~
+
+o Early userspace and 64 bit dev_t will allow the removal of most of
+  dasd_devmap.c and dasd_genhd.c.
+
+  PRI2
+
+o The 3270 console driver needs to be replaced with a working one
+  (prototype is there, needs to be finished).
+
+  PRI2
+
+o Minor interface changes are pending in cio/ when the z990 machines are
+  out.
+
+  PRI2
+
+o Jan Glauber is working on a fix for the timer issues related to running
+  on virtualized CPUs (wall-clock vs.  cpu time).
+
+  PRI1
+
+o a block device driver for ramdisks shared among virtual machines
+
+  PRI3
+
+o driver for crypto hardware
+
+  PRI3
+
+o 'claw' network device driver
+
+  PRI3
+
--- diff/Documentation/sound/alsa/Audigy-mixer.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/sound/alsa/Audigy-mixer.txt	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,345 @@
+
+		Sound Blaster Audigy mixer / default DSP code
+		===========================================
+
+This is based on SB-Live-mixer.txt.
+
+The EMU10K2 chips have a DSP part which can be programmed to support 
+various ways of sample processing, which is described here.
+(This acticle does not deal with the overall functionality of the 
+EMU10K2 chips. See the manuals section for further details.)
+
+The ALSA driver programs this portion of chip by default code
+(can be altered later) which offers the following functionality:
+
+
+1) Digital mixer controls
+-------------------------
+
+These controls are built using the DSP instructions. They offer extended
+functionality. Only the default build-in code in the ALSA driver is described
+here. Note that the controls work as attenuators: the maximum value is the 
+neutral position leaving the signal unchanged. Note that if the  same destination 
+is mentioned in multiple controls, the signal is accumulated and can be wrapped 
+(set to maximal or minimal value without checking of overflow).
+
+
+Explanation of used abbreviations:
+
+DAC    - digital to analog converter
+ADC    - analog to digital converter
+I2S    - one-way three wire serial bus for digital sound by Philips Semiconductors
+         (this standard is used for connecting standalone DAC and ADC converters)
+LFE    - low frequency effects (subwoofer signal)
+AC97   - a chip containing an analog mixer, DAC and ADC converters
+IEC958 - S/PDIF
+FX-bus - the EMU10K2 chip has an effect bus containing 64 accumulators.
+         Each of the synthesizer voices can feed its output to these accumulators
+         and the DSP microcontroller can operate with the resulting sum.
+
+name='PCM Front Playback Volume',index=0
+
+This control is used to attenuate samples for left and right front PCM FX-bus
+accumulators. ALSA uses accumulators 8 and 9 for left and right front PCM 
+samples for 5.1 playback. The result samples are forwarded to the front DAC PCM 
+slots of the Philips DAC.
+
+name='PCM Surround Playback Volume',index=0
+
+This control is used to attenuate samples for left and right surround PCM FX-bus
+accumulators. ALSA uses accumulators 2 and 3 for left and right surround PCM 
+samples for 5.1 playback. The result samples are forwarded to the surround DAC PCM 
+slots of the Philips DAC.
+
+name='PCM Center Playback Volume',index=0
+
+This control is used to attenuate samples for center PCM FX-bus accumulator.
+ALSA uses accumulator 6 for center PCM sample for 5.1 playback. The result sample
+is forwarded to the center DAC PCM slot of the Philips DAC.
+
+name='PCM LFE Playback Volume',index=0
+
+This control is used to attenuate sample for LFE PCM FX-bus accumulator. 
+ALSA uses accumulator 7 for LFE PCM sample for 5.1 playback. The result sample 
+is forwarded to the LFE DAC PCM slot of the Philips DAC.
+
+name='PCM Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples for
+stereo playback. The result samples are forwarded to the front DAC PCM slots 
+of the Philips DAC.
+
+name='PCM Capture Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulator. ALSA uses accumulators 0 and 1 for left and right PCM.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Music Playback Volume',index=0
+
+This control is used to attenuate samples for left and right MIDI FX-bus
+accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples.
+The result samples are forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='Music Capture Volume',index=0
+
+These controls are used to attenuate samples for left and right MIDI FX-bus
+accumulator. ALSA uses accumulators 4 and 5 for left and right PCM.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Mic Playback Volume',index=0
+
+This control is used to attenuate samples for left and right Mic input.
+For Mic input is used AC97 codec. The result samples are forwarded to 
+the front DAC PCM slots of the Philips DAC. Samples are forwarded to Mic
+capture FIFO (device 1 - 16bit/8KHz mono) too without volume control.
+
+name='Mic Capture Volume',index=0
+
+This control is used to attenuate samples for left and right Mic input.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Audigy CD Playback Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 TTL
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the front DAC PCM slots of the Philips DAC.
+
+name='Audigy CD Capture Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 TTL
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the ADC capture FIFO (thus to the standard capture PCM device).
+
+name='IEC958 Optical Playback Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 optical
+digital input. The result samples are forwarded to the front DAC PCM slots
+of the Philips DAC.
+
+name='IEC958 Optical Capture Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 optical
+digital inputs. The result samples are forwarded to the ADC capture FIFO
+(thus to the standard capture PCM device).
+
+name='Line2 Playback Volume',index=0
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs (on the AudigyDrive). The result samples are forwarded to the front
+DAC PCM slots of the Philips DAC.
+
+name='Line2 Capture Volume',index=1
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs (on the AudigyDrive). The result samples are forwarded to the ADC
+capture FIFO (thus to the standard capture PCM device).
+
+name='Analog Mix Playback Volume',index=0
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs from Philips ADC. The result samples are forwarded to the front
+DAC PCM slots of the Philips DAC. This contains mix from analog sources
+like CD, Line In, Aux, ....
+
+name='Analog Mix Capture Volume',index=1
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs Philips ADC. The result samples are forwarded to the ADC
+capture FIFO (thus to the standard capture PCM device).
+
+name='Aux2 Playback Volume',index=0
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs (on the AudigyDrive). The result samples are forwarded to the front
+DAC PCM slots of the Philips DAC.
+
+name='Aux2 Capture Volume',index=1
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs (on the AudigyDrive). The result samples are forwarded to the ADC
+capture FIFO (thus to the standard capture PCM device).
+
+name='Front Playback Volume',index=0
+
+All stereo signals are mixed together and mirrored to surround, center and LFE.
+This control is used to attenuate samples for left and right front speakers of
+this mix.
+
+name='Surround Playback Volume',index=0
+
+All stereo signals are mixed together and mirrored to surround, center and LFE.
+This control is used to attenuate samples for left and right surround speakers of
+this mix.
+
+name='Center Playback Volume',index=0
+
+All stereo signals are mixed together and mirrored to surround, center and LFE.
+This control is used to attenuate sample for center speaker of this mix.
+
+name='LFE Playback Volume',index=0
+
+All stereo signals are mixed together and mirrored to surround, center and LFE.
+This control is used to attenuate sample for LFE speaker of this mix.
+
+name='Tone Control - Switch',index=0
+
+This control turns the tone control on or off. The samples for front, rear
+and center / LFE outputs are affected.
+
+name='Tone Control - Bass',index=0
+
+This control sets the bass intensity. There is no neutral value!!
+When the tone control code is activated, the samples are always modified.
+The closest value to pure signal is 20.
+
+name='Tone Control - Treble',index=0
+
+This control sets the treble intensity. There is no neutral value!!
+When the tone control code is activated, the samples are always modified.
+The closest value to pure signal is 20.
+
+name='Master Playback Volume',index=0
+
+This control is used to attenuate samples for front, surround, center and 
+LFE outputs.
+
+name='IEC958 Optical Raw Playback Switch',index=0
+
+If this switch is on, then the samples for the IEC958 (S/PDIF) digital
+output are taken only from the raw FX8010 PCM, otherwise standard front
+PCM samples are taken.
+
+
+2) PCM stream related controls
+------------------------------
+
+name='EMU10K1 PCM Volume',index 0-31
+
+Channel volume attenuation in range 0-0xffff. The maximum value (no
+attenuation) is default. The channel mapping for three values is
+as follows:
+
+	0 - mono, default 0xffff (no attenuation)
+	1 - left, default 0xffff (no attenuation)
+	2 - right, default 0xffff (no attenuation)
+
+name='EMU10K1 PCM Send Routing',index 0-31
+
+This control specifies the destination - FX-bus accumulators. There 24
+values with this mapping:
+
+	 0 -  mono, A destination (FX-bus 0-63), default 0
+	 1 -  mono, B destination (FX-bus 0-63), default 1
+	 2 -  mono, C destination (FX-bus 0-63), default 2
+	 3 -  mono, D destination (FX-bus 0-63), default 3
+	 4 -  mono, E destination (FX-bus 0-63), default 0
+	 5 -  mono, F destination (FX-bus 0-63), default 0
+	 6 -  mono, G destination (FX-bus 0-63), default 0
+	 7 -  mono, H destination (FX-bus 0-63), default 0
+	 8 -  left, A destination (FX-bus 0-63), default 0
+	 9 -  left, B destination (FX-bus 0-63), default 1
+	10 -  left, C destination (FX-bus 0-63), default 2
+	11 -  left, D destination (FX-bus 0-63), default 3
+	12 -  left, E destination (FX-bus 0-63), default 0
+	13 -  left, F destination (FX-bus 0-63), default 0
+	14 -  left, G destination (FX-bus 0-63), default 0
+	15 -  left, H destination (FX-bus 0-63), default 0
+	16 - right, A destination (FX-bus 0-63), default 0
+	17 - right, B destination (FX-bus 0-63), default 1
+	18 - right, C destination (FX-bus 0-63), default 2
+	19 - right, D destination (FX-bus 0-63), default 3
+	20 - right, E destination (FX-bus 0-63), default 0
+	21 - right, F destination (FX-bus 0-63), default 0
+	22 - right, G destination (FX-bus 0-63), default 0
+	23 - right, H destination (FX-bus 0-63), default 0
+
+Don't forget that it's illegal to assign a channel to the same FX-bus accumulator 
+more than once (it means 0=0 && 1=0 is an invalid combination).
+ 
+name='EMU10K1 PCM Send Volume',index 0-31
+
+It specifies the attenuation (amount) for given destination in range 0-255.
+The channel mapping is following:
+
+	 0 -  mono, A destination attn, default 255 (no attenuation)
+	 1 -  mono, B destination attn, default 255 (no attenuation)
+	 2 -  mono, C destination attn, default 0 (mute)
+	 3 -  mono, D destination attn, default 0 (mute)
+	 4 -  mono, E destination attn, default 0 (mute)
+	 5 -  mono, F destination attn, default 0 (mute)
+	 6 -  mono, G destination attn, default 0 (mute)
+	 7 -  mono, H destination attn, default 0 (mute)
+	 8 -  left, A destination attn, default 255 (no attenuation)
+	 9 -  left, B destination attn, default 0 (mute)
+	10 -  left, C destination attn, default 0 (mute)
+	11 -  left, D destination attn, default 0 (mute)
+	12 -  left, E destination attn, default 0 (mute)
+	13 -  left, F destination attn, default 0 (mute)
+	14 -  left, G destination attn, default 0 (mute)
+	15 -  left, H destination attn, default 0 (mute)
+	16 - right, A destination attn, default 0 (mute)
+	17 - right, B destination attn, default 255 (no attenuation)
+	18 - right, C destination attn, default 0 (mute)
+	19 - right, D destination attn, default 0 (mute)
+	20 - right, E destination attn, default 0 (mute)
+	21 - right, F destination attn, default 0 (mute)
+	22 - right, G destination attn, default 0 (mute)
+	23 - right, H destination attn, default 0 (mute)
+
+
+
+4) MANUALS/PATENTS:
+-------------------
+
+ftp://opensource.creative.com/pub/doc
+-------------------------------------
+
+        Files:
+        LM4545.pdf      AC97 Codec
+
+        m2049.pdf       The EMU10K1 Digital Audio Processor
+
+        hog63.ps        FX8010 - A DSP Chip Architecture for Audio Effects
+
+
+WIPO Patents
+------------
+        Patent numbers:
+        WO 9901813 (A1) Audio Effects Processor with multiple asynchronous (Jan. 14, 1999)
+                        streams
+
+        WO 9901814 (A1) Processor with Instruction Set for Audio Effects (Jan. 14, 1999)
+
+        WO 9901953 (A1) Audio Effects Processor having Decoupled Instruction
+                        Execution and Audio Data Sequencing (Jan. 14, 1999)
+
+
+US Patents (http://www.uspto.gov/)
+----------------------------------
+
+        US 5925841      Digital Sampling Instrument employing cache memory (Jul. 20, 1999)
+
+        US 5928342      Audio Effects Processor integrated on a single chip (Jul. 27, 1999)
+                        with a multiport memory onto which multiple asynchronous
+                        digital sound samples can be concurrently loaded
+
+        US 5930158      Processor with Instruction Set for Audio Effects (Jul. 27, 1999)
+
+        US 6032235      Memory initialization circuit (Tram) (Feb. 29, 2000)
+
+        US 6138207      Interpolation looping of audio samples in cache connected to    (Oct. 24, 2000)
+                        system bus with prioritization and modification of bus transfers
+                        in accordance with loop ends and minimum block sizes
+
+        US 6151670      Method for conserving memory storage using a (Nov. 21, 2000)
+                        pool of  short term memory registers
+
+        US 6195715      Interrupt control for multiple programs communicating with      (Feb. 27, 2001)
+                        a common interrupt by associating programs to GP registers,
+                        defining interrupt register, polling GP registers, and invoking
+                        callback routine associated with defined interrupt register
--- diff/arch/i386/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/kgdb_stub.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,2454 @@
+/*
+ *
+ * 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, 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.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 400
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 64
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ */
+enum regnames { _EAX,		/* 0 */
+	_ECX,			/* 1 */
+	_EDX,			/* 2 */
+	_EBX,			/* 3 */
+	_ESP,			/* 4 */
+	_EBP,			/* 5 */
+	_ESI,			/* 6 */
+	_EDI,			/* 7 */
+	_PC /* 8 also known as eip */ ,
+	_PS /* 9 also known as eflags */ ,
+	_CS,			/* 10 */
+	_SS,			/* 11 */
+	_DS,			/* 12 */
+	_ES,			/* 13 */
+	_FS,			/* 14 */
+	_GS			/* 15 */
+};
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_tsc;
+	int errcode;
+	int vector;
+	int print_debug_info;
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define LOOKASIDE_SIZE 200	/* should be more than enough */
+#define MALLOC_MAX   200	/* Max malloc size */
+struct {
+	unsigned int esp;
+	int array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+static int trap_cpu;
+static unsigned int OLD_esp;
+
+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		return tty_getDebugChar();
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+__asm__("fn_rtn_stub:\n\t"
+	"movl %eax,%esp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addl $-4,%ebx\n\t"
+	"movl (%ebx), %eax\n\t"
+	"pushl %eax\n\t"
+	"cmpl %esp,%ecx\n\t"
+	"jne  1b\n\t"
+	"popl %eax\n\t"
+	"popl %ebx\n\t"
+	"popl %ecx\n\t"
+	"iret \n\t");
+/*					     *INDENT-ON*  */
+#define gdb_i386vector	kgdb_info.vector
+#define gdb_i386errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(&regs);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static short error;
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("EAX=%08lx ", regs->eax);
+	printk("EBX=%08lx ", regs->ebx);
+	printk("ECX=%08lx ", regs->ecx);
+	printk("EDX=%08lx ", regs->edx);
+	printk("\n");
+	printk("ESI=%08lx ", regs->esi);
+	printk("EDI=%08lx ", regs->edi);
+	printk("EBP=%08lx ", regs->ebp);
+	printk("ESP=%08lx ", (long) &regs->esp);
+	printk("\n");
+	printk(" DS=%08x ", regs->xds);
+	printk(" ES=%08x ", regs->xes);
+	printk(" SS=%08x ", __KERNEL_DS);
+	printk(" FL=%08lx ", regs->eflags);
+	printk("\n");
+	printk(" CS=%08x ", regs->xcs);
+	printk(" IP=%08lx ", regs->eip);
+#if 0
+	printk(" FS=%08x ", regs->fs);
+	printk(" GS=%08x ", regs->gs);
+#endif
+	printk("\n");
+
+}				/* print_regs */
+
+#define NEW_esp fn_call_lookaside[trap_cpu].esp
+
+static void
+regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_EAX] = regs->eax;
+	gdb_regs[_EBX] = regs->ebx;
+	gdb_regs[_ECX] = regs->ecx;
+	gdb_regs[_EDX] = regs->edx;
+	gdb_regs[_ESI] = regs->esi;
+	gdb_regs[_EDI] = regs->edi;
+	gdb_regs[_EBP] = regs->ebp;
+	gdb_regs[_DS] = regs->xds;
+	gdb_regs[_ES] = regs->xes;
+	gdb_regs[_PS] = regs->eflags;
+	gdb_regs[_CS] = regs->xcs;
+	gdb_regs[_PC] = regs->eip;
+	/* Note, as we are a debugging the kernel, we will always
+	 * trap in kernel code, this means no priviledge change,
+	 * and so the pt_regs structure is not completely valid.  In a non
+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
+	 * SS and ESP are not stacked, this means that the last 2 elements of
+	 * pt_regs is not valid (they would normally refer to the user stack)
+	 * also, using regs+1 is no good because you end up will a value that is
+	 * 2 longs (8) too high.  This used to cause stepping over functions
+	 * to fail, so my fix is to use the address of regs->esp, which
+	 * should point at the end of the stack frame.	Note I have ignored
+	 * completely exceptions that cause an error code to be stacked, such
+	 * as double fault.  Stuart Hughes, Zentropix.
+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
+
+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
+	 */
+	gdb_regs[_ESP] = NEW_esp;
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+}				/* regs_to_gdb_regs */
+
+static void
+gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
+{
+	regs->eax = gdb_regs[_EAX];
+	regs->ebx = gdb_regs[_EBX];
+	regs->ecx = gdb_regs[_ECX];
+	regs->edx = gdb_regs[_EDX];
+	regs->esi = gdb_regs[_ESI];
+	regs->edi = gdb_regs[_EDI];
+	regs->ebp = gdb_regs[_EBP];
+	regs->xds = gdb_regs[_DS];
+	regs->xes = gdb_regs[_ES];
+	regs->eflags = gdb_regs[_PS];
+	regs->xcs = gdb_regs[_CS];
+	regs->eip = gdb_regs[_PC];
+	NEW_esp = gdb_regs[_ESP];	/* keep the value */
+#if 0				/* can't change these */
+	regs->esp = gdb_regs[_ESP];
+	regs->xss = gdb_regs[_SS];
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+
+}				/* gdb_regs_to_regs */
+
+int thread_list = 0;
+
+void
+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs)
+{
+	unsigned long stack_page;
+	int count = 0;
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(gdb_regs, regs);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task) {
+			regs_to_gdb_regs(gdb_regs,
+					 kgdb_info.cpus_waiting[i].regs);
+			gdb_regs[_ESP] =
+			    (int) &kgdb_info.cpus_waiting[i].regs->esp;
+
+			return;
+		}
+	}
+#endif
+	memset(gdb_regs, 0, NUMREGBYTES);
+	gdb_regs[_ESP] = p->thread.esp;
+	gdb_regs[_PC] = p->thread.eip;
+	gdb_regs[_EBP] = *(int *) gdb_regs[_ESP];
+	gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4);
+	gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8);
+
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with.  This code was shamelessly purloined from process.c.  It was
+ * then enhanced to provide more registers than simply the program
+ * counter.
+ */
+
+	if (!thread_list) {
+		return;
+	}
+
+	if (p->state == TASK_RUNNING)
+		return;
+	stack_page = (unsigned long) p->thread_info;
+	if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] >
+	    THREAD_SIZE - sizeof(long) + stack_page)
+		return;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	do {
+		if (gdb_regs[_EBP] < stack_page ||
+		    gdb_regs[_EBP] > THREAD_SIZE - 2*sizeof(long) + stack_page)
+			return;
+		gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4);
+		gdb_regs[_ESP] = gdb_regs[_EBP] + 8;
+		gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP];
+		if (!in_sched_functions(gdb_regs[_PC]))
+			return;
+	} while (count++ < 16);
+	return;
+}
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	/*
+	 * This code traps references to the area mapped to the kernel
+	 * stack as given by the regs and, instead, stores to the
+	 * fn_call_lookaside[cpu].array
+	 */
+	if (may_fault &&
+	    (unsigned int) addr < OLD_esp &&
+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { {enabled:0},
+		   {enabled:0},
+		   {enabled:0},
+		   {enabled:0}};
+/* *INDENT-ON*	*/
+unsigned hw_breakpoint_status;
+void
+correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned dr7;
+
+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
+		      :);
+	/* *INDENT-OFF*	 */
+	do {
+		unsigned addr0, addr1, addr2, addr3;
+		asm volatile ("movl %%db0, %0\n"
+			      "movl %%db1, %1\n"
+			      "movl %%db2, %2\n"
+			      "movl %%db3, %3\n"
+			      :"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3)
+			      :);
+	} while (0);
+	/* *INDENT-ON*	*/
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movl %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movl %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movl %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movl %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+int
+in_kgdb(struct pt_regs *regs)
+{
+	unsigned flags;
+	int cpu = smp_processor_id();
+	in_kgdb_called = 1;
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			return 1;
+		}
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	kgdb_local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	kgdb_local_irq_restore(flags);
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	ack_APIC_irq();
+	in_kgdb(&regs);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+kgdb_handle_exception(int exceptionVector,
+		      int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	int addr, length;
+	int breakno, breaktype;
+	char *ptr;
+	int newPC;
+	threadref thref;
+	int threadid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+	int gdb_regs[NUMREGBYTES / 4];
+	int dr6;
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	regs	(*linux_regs)
+#define NUMREGS NUMREGBYTES/4
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(&regs);
+		return (0);
+	}
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	kgdb_local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	rdtscll(kgdb_info.entry_tsc);
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		int time = 0, end_time, dum = 0;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		rdtsc(dum, time);
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task &&
+					    in_kgdb_here_log[j]) {
+
+						int wait = 100000;
+						while (wait--) ;
+						if (!waiting_cpus[j].task &&
+						    in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+							    (struct task_struct
+							     *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				rdtsc(dum, time);
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %d cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&regs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+/*				       *INDENT-OFF*  */
+      __asm__("movl %0,%%db7"
+	      :	/* no output */
+	      :"r"(0));
+
+	asm volatile ("movl %%db6, %0\n"
+		      :"=r" (hw_breakpoint_status)
+		      :);
+
+/*				       *INDENT-ON*  */
+	switch (exceptionVector) {
+	case 0:		/* divide error */
+	case 1:		/* debug exception */
+	case 2:		/* NMI */
+	case 3:		/* breakpoint */
+	case 4:		/* overflow */
+	case 5:		/* bounds check */
+	case 6:		/* invalid opcode */
+	case 7:		/* device not available */
+	case 8:		/* double fault (errcode) */
+	case 10:		/* invalid TSS (errcode) */
+	case 12:		/* stack fault (errcode) */
+	case 16:		/* floating point error */
+	case 17:		/* alignment check (errcode) */
+	default:		/* any undocumented */
+		break;
+	case 11:		/* segment not present (errcode) */
+	case 13:		/* general protection (errcode) */
+	case 14:		/* page fault (special errcode) */
+	case 19:		/* cache flush denied */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			/* make valid address */
+			regs.eax = (long) &garbage_loc;
+			/* make valid address */
+			regs.edx = (long) &garbage_loc;
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&regs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+	kgdb_info.called_from = __builtin_return_address(0);
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+	trap_cpu = smp_processor_id();
+	OLD_esp = NEW_esp = (int) (&linux_regs->esp);
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	    remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, &regs, gdb_regs);
+			mem2hex((char *) gdb_regs,
+				remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).	 These may have
+				 * meaning for ptrace, but for us it is safe to
+				 * ignor them.	We do this by dumping them into
+				 * _GS which we also ignor, but do have memory for.
+				 */
+				int regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(gdb_regs, &regs);
+				if ((!usethread || usethread == current) &&
+				    hexToInt(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					regno =
+					    (regno >= NUMREGS ? _GS : regno);
+					hex2mem(ptr, (char *) &gdb_regs[regno],
+						4, 0);
+					gdb_regs_to_regs(gdb_regs, &regs);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				mem2hex((char *) addr,
+					remcomOutBuffer, length, 1);
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
+				hex2mem(ptr, (char *) addr, length, 1);
+
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				} else {
+					strcpy(remcomOutBuffer, "OK");
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%x\n", addr);
+
+				regs.eip = addr;
+			}
+
+			newPC = regs.eip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&regs);
+			}
+			asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+				      :);
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno) &&
+					    (breakinfo[breakno].type == 0)) {
+						/* Set restore flag */
+						regs.eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			asm volatile ("movl %0, %%db6\n"::"r" (0));
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToInt(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		case 'r':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			/* triplefault	 no return from here */
+			{
+				static long no_idt[2];
+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
+				BREAKPOINT;
+			}
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+	/*
+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
+	 * will be changed if we are trying to do this.	 We handle both
+	 * adding and subtracting, thus allowing gdb to put grung on
+	 * the stack which it removes later.
+	 */
+	if (NEW_esp != OLD_esp) {
+		int *ptr = END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp)
+			ptr -= (OLD_esp - NEW_esp) / sizeof (int);
+		*--ptr = linux_regs->eflags;
+		*--ptr = linux_regs->xcs;
+		*--ptr = linux_regs->eip;
+		*--ptr = linux_regs->ecx;
+		*--ptr = linux_regs->ebx;
+		*--ptr = linux_regs->eax;
+		linux_regs->ecx = NEW_esp - (sizeof (int) * 6);
+		linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp) {
+			linux_regs->eip = (unsigned int) fn_call_stub;
+		} else {
+			linux_regs->eip = (unsigned int) fn_rtn_stub;
+			linux_regs->eax = NEW_esp;
+		}
+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
+	}
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+		if (!(ss_hold)) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		kgdb_local_irq_restore(flags);
+		return (0);
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	kgdb_local_irq_restore(flags);
+	return (0);
+}
+
+/* this function is used to set up exception handlers for tracing and
+ * breakpoints.
+ * This function is not needed as the above line does all that is needed.
+ * We leave it for backward compatitability...
+ */
+void
+set_debug_traps(void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+
+	 * But really folks, every hear of labeled common, an old Fortran
+	 * concept.  Lots of folks can reference it and it is define if
+	 * anyone does.	 Only one can initialize it at link time.  We do
+	 * this with the hook.	See the statement above.  No need for any
+	 * executable code and it is ready as soon as the kernel is
+	 * loaded.  Very desirable in kernel debugging.
+
+	 linux_debug_hook = handle_exception ;
+	 */
+
+	/* In case GDB is started before us, ack any packets (presumably
+	   "$?#xx") sitting there.
+	   putDebugChar ('+');
+
+	   initialized = 1;
+	 */
+}
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_i386vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	int flags;
+	kgdb_local_irq_save(flags);
+	spin_lock(&ts_spin);
+	rdtscll(kgdb_and_then->at_time);
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	kgdb_local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/i386/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/lib/kgdb_serial.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,499 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b) outb_p(b,a)
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_p(info->port + UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_p(info->port + UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_p(chr, info->port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, 0);
+	outb_px(0xff, 0x080);
+	scratch2 = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_p(port + UART_LCR);
+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(port + UART_LCR, 0);
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_p(port + UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_p(port + UART_MCR);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
+	outb_px(port + UART_MCR, scratch);
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	int port = info->port;
+
+	(void) inb_p(port + UART_RX);
+	outb_px(port + UART_IER, 0);
+
+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_p(port + UART_MSR);
+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(port + UART_MCR, info->MCR);
+
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr, dum, time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	rdtsc(dum, time);
+	end_time = time + 2;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		rdtsc(dum, time);
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+#ifdef CONFIG_DISCONTIGMEM
+static inline int kgdb_mem_init_done(void)
+{
+	return highmem_start_page != NULL;
+}
+#else
+static inline int kgdb_mem_init_done(void)
+{
+	return max_mapnr != 0;
+}
+#endif
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info->port + UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+module_init(kgdb_enable_ints);
--- diff/arch/ia64/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ia64/kernel/kgdb_stub.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,2978 @@
+/*
+ *
+ * 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, 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.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <asm/unwind.h>
+#include <asm/delay.h>
+#include <asm/sections.h>
+#include <linux/irq.h>
+#include <linux/reboot.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+
+/*
+ * IA64 ToDo:
+ *	1) more testing needs to be done when modifying registers.
+ *	2) probably could use cleanup in register get/put from unw_info but gdb work
+ *	   is on going (WIP) to reduce g-packet on wire for serial
+ *	3) until gdb work is complete and accepted by gdb folks, the serial interface
+ *	   isn't complete.  the current g-packet is over 10,000 bytes which is too
+ *	   large for a serial line. without a g-packet a delay is used with large putpacket
+	   requests.  however, this won't solve a gdb sent packet which is a g-packet.
+ *	4) NMI for hung machine.  Well we don't have real NMI!
+ */
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+/* purloined from gdb ia64 config support */
+#define NUM_REGS 590
+#define REGISTER_BYTES (NUM_REGS*8+128*8)
+#define REGISTER_BYTE(N) (((N) * 8) \
+  + ((N) <= IA64_FR0_REGNUM ? 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM)))
+#define	REGISTER_SIZE(N) (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8)
+#define IA64_GR0_REGNUM         0
+#define IA64_FR0_REGNUM         128
+#define IA64_FR127_REGNUM       (IA64_FR0_REGNUM+127)
+#define IA64_PR0_REGNUM         256
+#define IA64_BR0_REGNUM         320
+#define IA64_VFP_REGNUM         328
+#define IA64_PR_REGNUM          330
+#define IA64_IP_REGNUM          331
+#define IA64_PSR_REGNUM         332
+#define IA64_CFM_REGNUM         333
+#define IA64_AR0_REGNUM         334
+#define IA64_NAT0_REGNUM        462
+#define IA64_NAT31_REGNUM       (IA64_NAT0_REGNUM+31)
+#define IA64_NAT32_REGNUM       (IA64_NAT0_REGNUM+32)
+#define IA64_RSC_REGNUM		(IA64_AR0_REGNUM+16)
+#define IA64_BSP_REGNUM		(IA64_AR0_REGNUM+17)
+#define IA64_BSPSTORE_REGNUM	(IA64_AR0_REGNUM+18)
+#define IA64_RNAT_REGNUM	(IA64_AR0_REGNUM+19)
+#define IA64_FCR_REGNUM		(IA64_AR0_REGNUM+21)
+#define IA64_EFLAG_REGNUM	(IA64_AR0_REGNUM+24)
+#define IA64_CSD_REGNUM		(IA64_AR0_REGNUM+25)
+#define IA64_SSD_REGNUM		(IA64_AR0_REGNUM+26)
+#define IA64_CFLG_REGNUM	(IA64_AR0_REGNUM+27)
+#define IA64_FSR_REGNUM		(IA64_AR0_REGNUM+28)
+#define IA64_FIR_REGNUM		(IA64_AR0_REGNUM+29)
+#define IA64_FDR_REGNUM		(IA64_AR0_REGNUM+30)
+#define IA64_CCV_REGNUM		(IA64_AR0_REGNUM+32)
+#define IA64_UNAT_REGNUM	(IA64_AR0_REGNUM+36)
+#define IA64_FPSR_REGNUM	(IA64_AR0_REGNUM+40)
+#define IA64_ITC_REGNUM		(IA64_AR0_REGNUM+44)
+#define IA64_PFS_REGNUM		(IA64_AR0_REGNUM+64)
+#define IA64_LC_REGNUM		(IA64_AR0_REGNUM+65)
+#define IA64_EC_REGNUM		(IA64_AR0_REGNUM+66)
+
+#define	REGISTER_INDEX(N)	(REGISTER_BYTE(N) / sizeof (unsigned long))
+#define BUFMAX (REGISTER_BYTES*2+10)
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static short error;
+/*
+ * gdb 'qPart' packet support
+ */
+
+struct reg_offset {
+	int 	regnum;
+	int	offset;
+} reg_offset[] = {
+{IA64_GR0_REGNUM+1, 0},			/*	r1 */
+{IA64_GR0_REGNUM+2, 8},
+{IA64_GR0_REGNUM+3, 16},
+{IA64_GR0_REGNUM+4, 24},
+{IA64_GR0_REGNUM+5, 32},
+{IA64_GR0_REGNUM+6, 40},
+{IA64_GR0_REGNUM+7, 48},
+{IA64_GR0_REGNUM+8, 56},
+{IA64_GR0_REGNUM+9, 64},
+{IA64_GR0_REGNUM+10, 72},
+{IA64_GR0_REGNUM+11, 80},
+{IA64_GR0_REGNUM+12, 88},
+{IA64_GR0_REGNUM+13, 96},
+{IA64_GR0_REGNUM+14, 104},
+{IA64_GR0_REGNUM+15, 112},
+{IA64_GR0_REGNUM+16, 120},
+{IA64_GR0_REGNUM+17, 128},
+{IA64_GR0_REGNUM+18, 136},
+{IA64_GR0_REGNUM+19, 144},
+{IA64_GR0_REGNUM+20, 152},
+{IA64_GR0_REGNUM+21, 160},
+{IA64_GR0_REGNUM+22, 168},
+{IA64_GR0_REGNUM+23, 176},
+{IA64_GR0_REGNUM+24, 184},
+{IA64_GR0_REGNUM+25, 192},
+{IA64_GR0_REGNUM+26, 200},
+{IA64_GR0_REGNUM+27, 208},
+{IA64_GR0_REGNUM+28, 216},
+{IA64_GR0_REGNUM+29, 224},
+{IA64_GR0_REGNUM+30, 232},
+{IA64_GR0_REGNUM+31, 240},		/* r31 */
+{IA64_FR0_REGNUM+6, 248},		/* fr6 */
+{IA64_FR0_REGNUM+7, 264},
+{IA64_FR0_REGNUM+8, 280},
+{IA64_FR0_REGNUM+9, 296},
+{IA64_FR0_REGNUM+10, 312},
+{IA64_FR0_REGNUM+11, 328},		/* fr11 */
+{IA64_PR_REGNUM, 344},			/* pr  */
+{IA64_BR0_REGNUM, 352},			/* b0 */
+{IA64_BR0_REGNUM+1, 360},
+{IA64_BR0_REGNUM+2, 368},
+{IA64_BR0_REGNUM+3, 376},
+{IA64_BR0_REGNUM+4, 384},
+{IA64_BR0_REGNUM+5, 392},
+{IA64_BR0_REGNUM+6, 400},
+{IA64_BR0_REGNUM+7, 408},		/* br7 */
+{IA64_IP_REGNUM,  416},			/* ip */
+{IA64_CFM_REGNUM, 424},			/* cfm */
+{IA64_RSC_REGNUM, 432},			/* rsc */
+{IA64_BSP_REGNUM, 440},			/* bp */
+{IA64_BSPSTORE_REGNUM, 448},		/* bpstore */
+{IA64_RNAT_REGNUM, 456},		/* rnat */
+{IA64_UNAT_REGNUM, 464},		/* unat */
+{IA64_FPSR_REGNUM, 472},		/* fpsr */
+{IA64_PSR_REGNUM,  480},		/* psr */
+{IA64_PFS_REGNUM,  488},		/* pfs */
+};
+
+static int rpacket_size;
+int norpacket_udelay = 10000;
+char * hex2mem(char *buf, char *mem, int count, int may_fault);
+char * mem2hex(char *mem, char *buf, int count, int may_fault);
+
+long
+find_roffset(long regnum)
+{
+	int i;
+
+	for (i = 0; i < (sizeof (reg_offset) / sizeof (reg_offset[0])); i++)
+		if (reg_offset[i].regnum == regnum)
+			return reg_offset[i].offset;
+
+	return -1L;
+}
+
+static void
+process_gpacket_request(void)
+{
+	int regnum, offset, size;
+
+	if (!rpacket_size)
+		rpacket_size = reg_offset[(sizeof (reg_offset) / sizeof (reg_offset[0])) - 1].
+			offset + 8;
+	hex2mem(&remcomInBuffer[20], (char *) &regnum, sizeof(regnum), 0);
+	if (remcomInBuffer[20 + sizeof(regnum)*2] != ',')
+		goto bad;
+	hex2mem(&remcomInBuffer[20 + sizeof(regnum)*2 + 1], (char *) &size, sizeof(size), 0);
+	if (size != sizeof (size))
+		goto bad;
+	offset = find_roffset(regnum);
+	mem2hex((char *) &offset, &remcomOutBuffer[0], sizeof (offset), 0);
+	remcomOutBuffer[sizeof(offset) * 2] = 0;
+	return;
+bad:
+	remcomOutBuffer[0] = 'E';
+	remcomOutBuffer[1] = 0;
+	return;
+}
+
+void
+rpacket_process(unsigned long *reg, char *buf, int direction)
+{
+	int i;
+
+	for (i = 0; i < (sizeof (reg_offset) / sizeof (reg_offset[0])); i++)
+		if (!direction)
+			hex2mem(buf + reg_offset[i].offset * 2,
+				(char *) &reg[REGISTER_INDEX(reg_offset[i].regnum)],
+				REGISTER_SIZE(reg_offset[i].regnum), 0);
+		else
+			mem2hex((char *) &reg[REGISTER_INDEX(reg_offset[i].regnum)],
+				buf + reg_offset[i].offset * 2,
+				REGISTER_SIZE(reg_offset[i].regnum), 0);
+
+	if (direction)
+		buf[rpacket_size * 2] = 0;
+}
+
+
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 	REGISTER_BYTES
+#define	BREAKNUM	0x6666UL
+#define	KGDBBREAKNUM	0x6665UL
+
+static void inline
+kgdb_pc(struct pt_regs *regs, unsigned long pc)
+{
+	regs->cr_iip = pc & ~0xf;
+	ia64_psr(regs)->ri = pc & 0x3;
+	return;
+}
+
+void
+breakpoint(void)
+{
+	asm volatile ("break.m 0x6665");
+}
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+struct kgdb_state {
+	int		exceptionVector;
+	int		signo;
+	unsigned long	err_code;
+	struct pt_regs *regs;
+	struct unw_frame_info
+			*unw;
+	int		ret;
+};
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_itc;
+	int errcode;
+	unsigned long vector;
+	int print_debug_info;
+	unsigned long ia64_regs[REGISTER_BYTES / sizeof(long)];
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+		unsigned long ia64_regs[REGISTER_BYTES / sizeof(long)];
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1UL};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define	MAX_HW_BREAKPOINT	(20)
+long hw_break_total_dbr, hw_break_total_ibr;
+#define	HW_BREAKPOINT	(hw_break_total_dbr + hw_break_total_ibr)
+#define	WATCH_INSTRUCTION	0x0
+#define WATCH_WRITE		0x1
+#define	WATCH_READ		0x2
+#define	WATCH_ACCESS		0x3
+
+#define	HWCAP_DBR	((1 << WATCH_WRITE) | (1 << WATCH_READ))
+#define	HWCAP_IBR	(1 << WATCH_INSTRUCTION)
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned long capable;
+	unsigned long type;
+	unsigned long mask;
+	unsigned long addr;
+} *breakinfo;
+
+#define LOOKASIDE_SIZE (200 + (sizeof(struct hw_breakpoint) * MAX_HW_BREAKPOINT))
+#define MALLOC_MAX   LOOKASIDE_SIZE	/* Max malloc size */
+struct {
+	unsigned int esp;
+	int array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		char ch;
+		while (1) {
+			ch = tty_getDebugChar() & 0x7f;
+			if (ch != 0x7f)
+				return ch;
+		}
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+/*__asm__("fn_rtn_stub:\n\t"
+	"movl %eax,%esp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addl $-4,%ebx\n\t"
+	"movl (%ebx), %eax\n\t"
+	"pushl %eax\n\t"
+	"cmpl %esp,%ecx\n\t"
+	"jne  1b\n\t"
+	"popl %eax\n\t"
+	"popl %ebx\n\t"
+	"popl %ecx\n\t"
+	"iret \n\t");
+*/
+/*					     *INDENT-ON*  */
+#define gdb_ia64vector	kgdb_info.vector
+#define gdb_ia64errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(linux_regs, unw_info);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum) {
+				putDebugChar('-');	/* failed checksum */
+			}
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+				if (!rpacket_size && ((count % 200) == 0))
+					udelay(norpacket_udelay);
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("B0=0x%lx\n", regs->b0);
+	printk("IPSR=0x%lx\n", regs->cr_ipsr);
+	printk("IIP=0x%lx\n", regs->cr_iip);
+	printk("\n");
+
+}				/* print_regs */
+
+
+
+static void
+unw_ar_regs(struct unw_frame_info *unw, unsigned long *regs, int put)
+{
+	if (put)
+		unw_access_ar(unw, UNW_AR_BSP, &regs[REGISTER_INDEX(IA64_BSP_REGNUM)], put);
+	else
+		unw_get_bsp(unw, &regs[REGISTER_INDEX(IA64_BSP_REGNUM)]);
+	unw_access_ar(unw, UNW_AR_BSPSTORE, &regs[REGISTER_INDEX(IA64_BSPSTORE_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_PFS, &regs[REGISTER_INDEX(IA64_PFS_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_RNAT, &regs[REGISTER_INDEX(IA64_RNAT_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_UNAT, &regs[REGISTER_INDEX(IA64_UNAT_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_LC, &regs[REGISTER_INDEX(IA64_LC_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_EC, &regs[REGISTER_INDEX(IA64_EC_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_FPSR, &regs[REGISTER_INDEX(IA64_FPSR_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_RSC, &regs[REGISTER_INDEX(IA64_RSC_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_CCV, &regs[REGISTER_INDEX(IA64_CCV_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_CSD, &regs[REGISTER_INDEX(IA64_CSD_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_SSD, &regs[REGISTER_INDEX(IA64_SSD_REGNUM)], put);
+	return;
+}
+
+static void
+unw_get_regs(struct unw_frame_info *unw, unsigned long *regs, struct pt_regs *ptregs)
+{
+	int i, j;
+	char nat;
+	struct ia64_fpreg *fr, freg;
+
+	memset(regs, 0, sizeof (kgdb_info.ia64_regs));
+
+	for (i = 1; i < 32; i++) {
+		unw_access_gr(unw, i, &regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)], &nat, 0);
+		regs[REGISTER_INDEX(IA64_NAT0_REGNUM + i)] = nat;
+	}
+
+	for (i = 1; i < 8; i++)
+		unw_access_br(unw, i, &regs[REGISTER_INDEX(IA64_BR0_REGNUM + i)], 0);
+
+	if (ptregs)
+		regs[REGISTER_INDEX(IA64_BR0_REGNUM)] = ptregs->b0;
+	else
+		unw_access_br(unw, 0, &regs[REGISTER_INDEX(IA64_BR0_REGNUM)], 0);
+
+	if (ptregs)
+		fr = &ptregs->f6;
+	else
+		fr = &freg;
+
+	for (i = 6; i < 12; i++) {
+		if (!ptregs)
+			unw_access_fr(unw, i, fr, 0);
+		regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i)] = fr->u.bits[0];
+		regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i + 1)] = fr->u.bits[1];
+		if (ptregs)
+			fr++;
+	}
+
+	unw_ar_regs(unw, regs, 0);
+
+	unw_access_pr(unw, &regs[REGISTER_INDEX(IA64_PR_REGNUM)], 0);
+	for (j = 1, i = 0; i < 64; i++, j <<= 1, i++)
+		regs[REGISTER_INDEX(IA64_PR0_REGNUM + i)] =
+			(regs[REGISTER_INDEX(IA64_PR_REGNUM)] & j) ? 1 : 0;
+
+
+	if (!ptregs) {
+		unw_get_ip(unw, &regs[REGISTER_INDEX(IA64_IP_REGNUM)]);
+		unw_get_cfm(unw, &regs[REGISTER_INDEX(IA64_CFM_REGNUM)]);
+	} else {
+		regs[REGISTER_INDEX(IA64_IP_REGNUM)] = ptregs->cr_iip;
+		regs[REGISTER_INDEX(IA64_PSR_REGNUM)] = ptregs->cr_ipsr;
+		regs[REGISTER_INDEX(IA64_CFM_REGNUM)] = ptregs->cr_ifs;
+	}
+
+	return;
+}
+
+static void
+kgdb_get_block_task(struct task_struct *p, unsigned long *ia64regs)
+{
+	struct unw_frame_info info;
+	unsigned long ip;
+	int count = 0;
+
+	unw_init_from_blocked_task(&info, p);
+	ip = 0UL;
+	do {
+		if (unw_unwind(&info) < 0)
+			return;
+		unw_get_ip(&info, &ip);
+		if (!in_sched_functions(ip))
+			break;
+	} while (count++ < 16);
+
+	if (!ip)
+		return;
+
+	unw_get_regs(&info, ia64regs, (struct pt_regs *) 0);
+
+	return;
+}
+
+static void
+regs_to_gdb_regs(struct kgdb_state *state)
+{
+	unw_get_regs(state->unw, kgdb_info.ia64_regs, state->regs);
+	return;
+}				/* regs_to_gdb_regs */
+
+static void
+gdb_regs_to_regs(struct kgdb_state *state)
+{
+	int i;
+	char nat;
+	unsigned long *regs;
+	struct ia64_fpreg *fr;
+	struct unw_frame_info *unw;
+
+	unw = state->unw;
+	regs = kgdb_info.ia64_regs;
+
+	for (i = 1; i < 32; i++) {
+		nat = (char) regs[REGISTER_INDEX(IA64_NAT0_REGNUM + i)];
+		unw_access_gr(unw, i, &regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)], &nat, 1);
+	}
+
+	for (i = 0; i < 8; i++)
+		unw_access_br(unw, i, &regs[REGISTER_INDEX(IA64_BR0_REGNUM + i)], 1);
+
+	for (fr = &state->regs->f6, i = 6; i < 12; i++, fr++) {
+		fr->u.bits[0] = regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i)];
+		fr->u.bits[1] = regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i + 1)];
+	}
+
+	unw_ar_regs(unw, regs, 1);
+
+	unw_access_pr(unw, &regs[IA64_PR_REGNUM], 1);
+
+	state->regs->cr_iip = regs[REGISTER_INDEX(IA64_IP_REGNUM)];
+	state->regs->cr_ipsr = regs[REGISTER_INDEX(IA64_PSR_REGNUM)];
+	state->regs->cr_ifs = regs[REGISTER_INDEX(IA64_CFM_REGNUM)];
+
+	return;
+
+}				/* gdb_regs_to_regs */
+
+int thread_list = 0;
+
+void
+get_gdb_regs(struct task_struct *p, struct kgdb_state *state)
+{
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(state);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task &&
+			!user_mode(kgdb_info.cpus_waiting[i].regs)){
+			memcpy(kgdb_info.ia64_regs, kgdb_info.cpus_waiting[i].ia64_regs,
+				sizeof(kgdb_info.ia64_regs));
+			return;
+		}
+	}
+#endif
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with. Some of this code was purloined from get_wchan;
+ */
+
+	if (!thread_list)
+		return;
+	else if (p->state == TASK_RUNNING)
+		return;
+
+	kgdb_get_block_task(p, kgdb_info.ia64_regs);
+
+	return;
+
+}
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	if (may_fault) {
+		unsigned long valid;
+		if ((unsigned long) addr < PAGE_SIZE)
+			valid = 0;
+		else
+			asm volatile("probe.w %0 = %1, 0" : "=r" (valid) : "r" (addr) : "memory");
+		if (!valid) {
+			mem_err = 1;
+			return;
+		}
+
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		if (may_fault) {
+			unsigned long valid;
+			if ((unsigned long) mem < PAGE_SIZE)
+				valid = 0;
+			else
+				asm volatile("probe.r %0 = %1, 0" :
+					"=r" (valid) : "r" (mem) : "memory");
+			if (!valid)
+				mem_err = 1;
+			else
+				ch = get_char(mem++);
+		}
+		else
+			ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToLong(char **ptr, unsigned long *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0UL;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+int
+hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+#ifdef	CONFIG_KGDB_EARLY
+struct task_struct kgdb_task = {.comm = "kgdb-dummy"};
+#endif
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+#ifdef	CONFIG_KGDB_EARLY
+	if (!kgdb_pid_init_done)
+		return &kgdb_task;
+#endif
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+
+
+unsigned long hw_breakpoint_status;
+
+int hw_breakpoint_init;
+
+void
+do_init_hw_break(void)
+{
+	s64 status;
+	int i;
+
+	hw_breakpoint_init = 1;
+
+#ifdef	CONFIG_IA64_HP_SIM
+	hw_break_total_ibr = 8;
+	hw_break_total_dbr = 8;
+	status = 0;
+#else
+	status = ia64_pal_debug_info(&hw_break_total_ibr, &hw_break_total_dbr);
+#endif
+
+	if (status) {
+		printk(KERN_INFO "do_init_hw_break: pal call failed %d\n", (int) status);
+		return;
+	}
+
+	if (HW_BREAKPOINT > MAX_HW_BREAKPOINT) {
+		printk(KERN_INFO "do_init_hw_break: %d exceeds max %d\n", (int) HW_BREAKPOINT,
+			(int) MAX_HW_BREAKPOINT);
+
+		while ((HW_BREAKPOINT > MAX_HW_BREAKPOINT) && hw_break_total_ibr != 1)
+			hw_break_total_ibr--;
+		while (HW_BREAKPOINT > MAX_HW_BREAKPOINT)
+			hw_break_total_dbr--;
+	}
+
+	breakinfo = malloc(HW_BREAKPOINT * sizeof(struct hw_breakpoint));
+
+	if (!breakinfo) {
+		printk(KERN_INFO "Failed to allocate hardware break array\n");
+		return;
+	}
+
+	memset(breakinfo, 0, HW_BREAKPOINT * sizeof(struct hw_breakpoint));
+
+	for (i = 0; i < hw_break_total_dbr; i++)
+		breakinfo[i].capable = HWCAP_DBR;
+
+	for (; i < HW_BREAKPOINT; i++)
+		breakinfo[i].capable = HWCAP_IBR;
+
+	return;
+}
+
+void
+correct_hw_break(void)
+{
+	int breakno;
+
+	if (!breakinfo)
+		return;
+
+	for (breakno = 0; breakno < HW_BREAKPOINT; breakno++) {
+		if (breakinfo[breakno].enabled) {
+			if (breakinfo[breakno].capable & HWCAP_IBR) {
+				int ibreakno = breakno - hw_break_total_dbr;
+				ia64_set_ibr(ibreakno << 1, breakinfo[breakno].addr);
+				ia64_set_ibr((ibreakno << 1) + 1,
+					(~breakinfo[breakno].mask & ((1UL << 56UL) - 1)) |
+					(1UL << 56UL) | (1UL << 63UL));
+			}
+			else {
+				ia64_set_dbr(breakno << 1, breakinfo[breakno].addr);
+				ia64_set_dbr((breakno << 1) + 1,
+					(~breakinfo[breakno].mask & ((1UL << 56UL) - 1)) |
+					(1UL << 56UL) | (breakinfo[breakno].type << 62UL));
+			}
+		}
+		else  {
+			if (breakinfo[breakno].capable & HWCAP_IBR)
+				ia64_set_ibr(((breakno - hw_break_total_dbr) << 1) + 1, 0);
+			else
+				ia64_set_dbr((breakno << 1) + 1, 0);
+		}
+	}
+
+	return;
+}
+
+int
+hardware_breakpoint(unsigned long addr, int length, int type, int action)
+{
+	int breakno, found, watch;
+	unsigned long mask;
+	extern unsigned long _start[];
+
+	if (!hw_breakpoint_init)
+		do_init_hw_break();
+
+	if (!breakinfo)
+		return 0;
+	else if (addr == (unsigned long) _start)
+		return 1;
+
+	if (type == WATCH_ACCESS)
+		mask = HWCAP_DBR;
+	else
+		mask = 1UL << type;
+
+	for (watch = 0, found = 0, breakno = 0; breakno < HW_BREAKPOINT; breakno++) {
+		if (action) {
+			if (breakinfo[breakno].enabled || !(breakinfo[breakno].capable & mask))
+				continue;
+			breakinfo[breakno].enabled = 1;
+			breakinfo[breakno].type = type;
+			breakinfo[breakno].mask = length - 1;
+			breakinfo[breakno].addr = addr;
+			watch = breakno;
+		} else if (breakinfo[breakno].enabled &&
+			((length < 0 && breakinfo[breakno].addr == addr) ||
+			((breakinfo[breakno].capable & mask) &&
+			(breakinfo[breakno].mask == (length - 1)) &&
+			(breakinfo[breakno].addr == addr)))) {
+			breakinfo[breakno].enabled = 0;
+			breakinfo[breakno].type = 0UL;
+		}
+		else
+			continue;
+		found++;
+		if (type != WATCH_ACCESS)
+			break;
+		else if (found == 2)
+			break;
+		else
+			mask = HWCAP_IBR;
+	}
+
+	if (type == WATCH_ACCESS && found == 1) {
+		breakinfo[watch].enabled = 0;
+		found = 0;
+	}
+
+	return found;
+}
+
+#ifdef	oldbreak_protocol
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled)
+		return -1;
+
+	breakinfo[breakno].enabled = 0;
+
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled)
+		return -1;
+
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].mask = len - 1;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+#endif
+
+static void inline
+normalize(struct unw_frame_info *running, struct pt_regs *regs)
+{
+	unsigned long sp;
+
+	/*
+	 * unwind to last frame before exception which will be an error
+	 * and then fetch the bsp at exception time.
+	 */
+
+	do {
+		unw_get_sp(running, &sp);
+		if ((sp + 0x10) >= (unsigned long) regs)
+			break;
+	} while (unw_unwind(running) >= 0);
+
+	return;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+
+static void
+snap_regs(struct unw_frame_info *unw_info, void *data)
+{
+	struct pt_regs *regs;
+	int cpu;
+
+	regs = data;
+	normalize(unw_info, regs);
+	cpu = smp_processor_id();
+	unw_get_regs(unw_info, kgdb_info.cpus_waiting[cpu].ia64_regs, regs);
+
+	return;
+}
+
+int
+in_kgdb(struct pt_regs *regs, struct unw_frame_info *unw_info)
+{
+	unsigned flags;
+	int cpu = smp_processor_id();
+	in_kgdb_called = 1;
+
+	preempt_disable();
+
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			preempt_enable_no_resched();
+			return 1;
+		}
+		preempt_enable_no_resched();
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	kgdb_local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	if (unw_info)
+		unw_get_regs(unw_info, kgdb_info.cpus_waiting[cpu].ia64_regs, regs);
+	else if (!user_mode(regs)) {
+		if (current->state == TASK_RUNNING)
+			unw_init_running(snap_regs, regs);
+		else
+			kgdb_get_block_task(current, kgdb_info.cpus_waiting[cpu].ia64_regs);
+	}
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	kgdb_local_irq_restore(flags);
+	preempt_enable_no_resched();
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	in_kgdb(&regs, NULL);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs, struct unw_frame_info *unw)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+
+static void do_kgdb_handle_exception(struct unw_frame_info *, void *data);
+
+int
+kgdb_handle_exception(int exceptionVector, int signo, unsigned long err_code, struct pt_regs *linux_regs)
+{
+	struct kgdb_state info;
+
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if (user_mode(linux_regs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(linux_regs);
+		return (0);
+	}
+
+	preempt_disable();
+
+	kgdb_info.called_from = __builtin_return_address(0);
+
+	info.exceptionVector = exceptionVector;
+	info.signo = signo;
+	info.err_code = err_code;
+	info.regs = linux_regs;
+	info.unw = (void *) 0;
+	unw_init_running(do_kgdb_handle_exception, &info);
+
+	preempt_enable_no_resched();
+
+	return info.ret;
+}
+
+static int kgdb_dbregs_enabled;
+
+static void
+do_kgdb_handle_exception(struct unw_frame_info *unw_info, void *data)
+{
+	int exceptionVector, signo, have_regs = 0;
+	unsigned long err_code;
+	struct pt_regs *linux_regs;
+	struct kgdb_state *info;
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	int length;
+	unsigned long addr;
+	char *ptr;
+	int newPC;
+	threadref thref;
+	int threadid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+#define	gdb_regs	kgdb_info.ia64_regs
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	ptregs	(*linux_regs)
+#define NUMREGS NUM_REGS
+
+	info = data;
+	info->unw = unw_info;
+	exceptionVector = info->exceptionVector;
+	signo = info->signo;
+	err_code = info->err_code;
+	linux_regs = info->regs;
+
+	normalize(unw_info, linux_regs);
+
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	kgdb_local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	kgdb_info.entry_itc = ia64_get_itc();
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		long time = 0, end_time;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		time = ia64_get_itc();
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task && in_kgdb_here_log[j]) {
+						int wait = 100000;
+						while (wait-- && !waiting_cpus[j].task );
+						if (!waiting_cpus[j].task  &&
+							in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+								(struct task_struct *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				time = ia64_get_itc();
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %ld cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%ld, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&ptregs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+	hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR);
+	if (hw_breakpoint_status & IA64_PSR_DB)
+		ia64_setreg(_IA64_REG_PSR_L, hw_breakpoint_status ^ IA64_PSR_DB);
+
+
+	switch (exceptionVector) {
+	case -1:	/* general death */
+	case 11:	/* break  fix signo */
+		switch (err_code) { 	/* break_num */
+		case BREAKNUM:
+			signo = SIGTRAP;
+			break;
+		case KGDBBREAKNUM:
+			signo = SIGTRAP;
+			if (ia64_psr(linux_regs)->ri < 2)
+				kgdb_pc(linux_regs, linux_regs->cr_iip +
+					ia64_psr(linux_regs)->ri + 1);
+			else
+				kgdb_pc(linux_regs, linux_regs->cr_iip + 16);
+			break;
+		}
+		break;
+	case 29:	/*  hardware breakpoint ibr/dbr fault */
+	case 36:	/* single step trap */
+		signo = SIGTRAP;
+		break;
+	case 6:		/* ikey_miss */
+	case 7:		/* dkey_miss */
+	case 24:	/* general exception */
+	case 31:	/*  unsupported data reference */
+		signo = SIGSEGV;
+		break;
+	case 13:	/* reserved  */
+	case 14:	/*  " ""     */
+	case 15:	/*  " ""     */
+	case 16:	/*  " ""     */
+	case 17:	/*  " ""     */
+	case 18:	/*  " ""     */
+	case 19:	/*  " ""     */
+	case 28:	/*  " ""     */
+	case 25:	/* disable fp */
+	case 32:	/* floating point */
+	case 33:	/* floating point trap */
+	case 34:	/* lower privilege fault */
+	case 35:	/* taken branch trap */
+	case 37:	/* reserved */
+	case 38:	/* reserved */
+	case 39:	/* reserved */
+	case 40:	/* reserved */
+	case 41:	/* reserved */
+	case 42:	/* reserved */
+	case 43:	/* reserved */
+	case 44:	/* reserved */
+	case 45:	/* ia32_exception */
+	case 47:	/* ia32 interrupt  */
+	default:	/* reserved and undefined */
+		signo = SIGILL;
+		break;
+	case 5:		/* kernel page fault */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			if (ia64_psr(linux_regs)->ri < 2)
+				kgdb_pc(linux_regs, linux_regs->cr_iip +
+					ia64_psr(linux_regs)->ri + 1);
+			else
+				kgdb_pc(linux_regs, linux_regs->cr_iip + 16);
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&ptregs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_ia64vector = exceptionVector;
+	gdb_ia64errcode = err_code;
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'p':	/* fetch register */
+		{
+			int regnum;
+
+			if (!have_regs) {
+				get_gdb_regs(usethread, info);
+				have_regs = 1;
+			}
+
+			hex2mem(&remcomInBuffer[1], (char *) &regnum, sizeof(regnum), 0);
+			if (regnum >= NUMREGS) {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = 0;
+				break;
+			}
+			mem2hex((char *) &gdb_regs[REGISTER_INDEX(regnum)], remcomOutBuffer,
+				REGISTER_SIZE(regnum), 0);
+			remcomOutBuffer[REGISTER_SIZE(regnum) * 2] = 0;
+			break;
+		}
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, info);
+			if (rpacket_size)
+				rpacket_process(gdb_regs, remcomOutBuffer, 1);
+			else
+				mem2hex((char *) gdb_regs,
+					remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			if (rpacket_size)
+				rpacket_process(gdb_regs, &remcomInBuffer[1], 0);
+			else
+			  hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(info);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).	 These may have
+				 * meaning for ptrace, but for us it is safe to
+				 * ignor them.	We do this by dumping them into
+				 * _GS which we also ignor, but do have memory for.
+				 */
+				int regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(info);
+				if ((!usethread || usethread == current) &&
+				    hexToInt(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					regno =
+					    (regno >= NUMREGS ? 0 : regno);
+					hex2mem(ptr, (char *) &gdb_regs[REGISTER_INDEX(regno)],
+						4, 0);
+					gdb_regs_to_regs(info);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				mem2hex((char *) addr,
+					remcomOutBuffer, length, 1);
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
+				extern unsigned long _start[];
+
+				if (addr == (unsigned long) _start)
+					strcpy(remcomOutBuffer, "OK");
+
+				else {
+					hex2mem(ptr, (char *) addr, length, 1);
+
+					if (mem_err) {
+						strcpy(remcomOutBuffer, "E03");
+						debug_error("memory fault\n", NULL);
+					} else {
+						if (kernel_text_address(addr))
+							flush_icache_range(addr, addr + length);
+						strcpy(remcomOutBuffer, "OK");
+					}
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%lx\n", addr);
+
+				ptregs.cr_iip = addr;
+			}
+
+			newPC = ptregs.cr_iip;
+
+			/* clear the trace bit */
+			ptregs.cr_ipsr &= ~IA64_PSR_SS;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				ptregs.cr_ipsr |= IA64_PSR_SS;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&ptregs);
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			ptregs.cr_ipsr |= IA64_PSR_DB;
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'P':
+				/* qPart:gpacket:read::<offset>,<size> */
+				if (strncmp(&remcomInBuffer[1], "Part", 4) ||
+					remcomInBuffer[5] != ':' ||
+					strncmp(&remcomInBuffer[6], "gpacket", 7) ||
+					remcomInBuffer[13] != ':' ||
+					strncmp(&remcomInBuffer[14], "read", 4) ||
+					remcomInBuffer[18] != ':' ||
+					remcomInBuffer[19] != ':')
+					break;
+				process_gpacket_request();
+				break;
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+#ifdef	oldbreak_protocol
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToLong(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+#endif
+		/*
+		 * Set/Remove watchpoint
+		 *
+		 */
+		case 'Z':
+		case 'z':
+			if (!kgdb_dbregs_enabled)
+				break;
+
+			switch (remcomInBuffer[1]) {
+			case '0':	/* insert hwd break */
+			case '1':	/* hardware breakpoint */
+			case '2':	/* write watchpoint */
+			case '3':	/* read watchpoint */
+			case '4':	/* access watchpoint */
+				if (remcomInBuffer[2] != ',') {
+					strcpy(remcomOutBuffer, "ERROR");
+					break;
+				}
+				ptr = &remcomInBuffer[3];
+				if (hexToLong(&ptr, &addr)) {
+					ptr++;
+					if (!hexToInt(&ptr, &length)) {
+						strcpy(remcomOutBuffer, "ERROR");
+						break;
+					}
+				}
+				else {
+					strcpy(remcomOutBuffer, "ERROR");
+					break;
+				}
+
+				if (hardware_breakpoint(addr, length,
+					(remcomInBuffer[1] != '0' ?
+					remcomInBuffer[1] - '1' : WATCH_INSTRUCTION),
+					remcomInBuffer[0] == 'Z'))
+					strcpy(remcomOutBuffer, "OK");
+				else
+					strcpy(remcomOutBuffer, "ERROR");
+				break;
+			default:
+				strcpy(remcomOutBuffer, "ERROR");
+				break;
+			}
+			break;
+		case 'R':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			machine_restart(NULL);
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (ptregs.cr_ipsr & IA64_PSR_SS) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (ptregs.cr_ipsr & IA64_PSR_SS)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+
+		if (!ss_hold) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		kgdb_local_irq_restore(flags);
+		info->ret = 0;
+		return;
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	kgdb_local_irq_restore(flags);
+	info->ret = 0;
+	return;
+}
+
+/* this function is used to set up exception handlers for tracing and
+ * breakpoints.
+ * This function is not needed as the above line does all that is needed.
+ * We leave it for backward compatitability...
+ */
+void
+set_debug_traps(void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+
+	 * But really folks, every hear of labeled common, an old Fortran
+	 * concept.  Lots of folks can reference it and it is define if
+	 * anyone does.	 Only one can initialize it at link time.  We do
+	 * this with the hook.	See the statement above.  No need for any
+	 * executable code and it is ready as soon as the kernel is
+	 * loaded.  Very desirable in kernel debugging.
+
+	 linux_debug_hook = handle_exception ;
+	 */
+
+	/* In case GDB is started before us, ack any packets (presumably
+	   "$?#xx") sitting there.
+	   putDebugChar ('+');
+
+	   initialized = 1;
+	 */
+}
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_ia64vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+int __init
+kgdb_enable_dbregs(char *str)
+{
+	kgdb_dbregs_enabled = 1;
+	return 1;
+}
+
+__setup("kgdb_debug_regs=", kgdb_enable_dbregs);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	int flags;
+	kgdb_local_irq_save(flags);
+	spin_lock(&ts_spin);
+	kgdb_and_then->at_time = ia64_get_itc();
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	kgdb_local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/ia64/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ia64/lib/kgdb_serial.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,584 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_core.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#include <asm/delay.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b,c) 		kgdb_serial_out(a, b, c)
+#define	outb_py(a, b, c)	kgdb_serial_out(b, c, a)
+#define	inb_py(ASYNC, OFF)	kgdb_serial_in(ASYNC, OFF)
+
+static void inline
+kgdb_serial_out(struct async_struct *serial, unsigned long offset, char ch)
+{
+	offset <<= serial->iomem_reg_shift;
+
+	switch(serial->io_type) {
+	case SERIAL_IO_MEM:
+		writeb(ch, serial->iomem_base + offset);
+		break;
+	default:
+		outb(serial->port + offset, ch);
+		break;
+	}
+	return;
+}
+
+static inline unsigned int
+kgdb_serial_in(struct async_struct *serial, unsigned long offset)
+{
+	unsigned int ch;
+
+	offset <<= serial->iomem_reg_shift;
+
+	switch(serial->io_type) {
+	case SERIAL_IO_MEM:
+		ch = readb(serial->iomem_base + offset);
+		break;
+	default:
+		ch = inb(serial->port + offset);
+		break;
+	}
+
+	return ch;
+}
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_py(info, UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_py(info, UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_py(info, UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_py(chr, info, UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_py(info,  UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_py(info, UART_IER);
+	outb_px(info, UART_IER, 0);
+	scratch2 = inb_py(info, UART_IER);
+	outb_px(info, UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_py(info, UART_LCR);
+	outb_px(info, UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(info, UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(info, UART_LCR, 0);
+	outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_py(info, UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_py(info, UART_MCR);
+	outb_px(info, UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_py(info, UART_MSR) & 0xF0;
+	outb_px(info, UART_MCR, scratch);
+#ifndef	CONFIG_SERIAL_8250_HCDP		/* HCDP seems to skip this test */
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	(void) inb_py(info, UART_RX);
+	outb_px(info, UART_IER, 0);
+
+	(void) inb_py(info, UART_RX);	/* serial driver comments say */
+	(void) inb_py(info, UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_py(info, UART_MSR);
+	outb_px(info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(info, UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(info, UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(info, UART_MCR, info->MCR);
+	printk("UART_LCR = 0x%x\n", inb_py(info, UART_LCR));
+
+	outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info, UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr;
+	volatile long time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	time = ia64_get_itc();
+	end_time = time + local_cpu_data->itm_delta * (HZ / 10);
+	if (!local_cpu_data->itm_delta)
+		end_time = time + 500;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		time = ia64_get_itc();
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		udelay(10000);
+//		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+static int mem_init_done = 1;
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+
+static inline int kgdb_mem_init_done(void)
+{
+	return mem_init_done;
+}
+
+#ifdef	CONFIG_KGDB_EARLY
+static struct irqaction kgdb_action;
+#endif
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+#ifndef	CONFIG_KGDB_EARLY
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+#else
+{
+		irq_desc_t *desc;
+		kgdb_action.handler = gdb_interrupt;
+		kgdb_action.flags = IRQ_T(gdb_async_info);
+		kgdb_action.mask = 0;
+		kgdb_action.name = "KGDB-stub";
+		kgdb_action.next = NULL;
+		kgdb_action.dev_id = NULL;
+		desc = irq_descp(gdb_async_info->state->irq);
+		if (desc->handler != &no_irq_type) {
+			desc->action = &kgdb_action;
+			ints_disabled = 0;
+			desc->depth = 0;
+			desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
+				IRQ_WAITING | IRQ_INPROGRESS);
+			desc->handler->startup(gdb_async_info->state->irq);
+		}
+		if (ints_disabled)
+			printk("kgdb_enable_ints_now: setup_irq failed\n");
+		else
+			printk("kgdb early access enabled\n");
+}
+#endif
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info, UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info, UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+void __init
+kgdb_serial_init(void)
+{
+	kgdb_enable_ints();
+	if (!ints_disabled) {
+		extern char saved_command_line[];
+		char *cp;
+		for (cp = saved_command_line; *cp; cp++)
+			if (memcmp(cp, "kgdb=1", 6) == 0) {
+				BREAKPOINT;
+				break;
+			}
+	}
+}
+
+#ifndef	CONFIG_IA64_HP_SIM
+late_initcall(kgdb_enable_ints);
+#endif
--- diff/arch/x86_64/Kconfig.kgdb	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/Kconfig.kgdb	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,176 @@
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb.txt file.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on KGDB
+	default  3f8
+	help
+	  Some systems (x86 family at this writing) allow the port
+	  address to be configured.  The number entered is assumed to be
+	  hex, don't put 0x in front of it.  The standard address are:
+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
+	  will tell you what you have.  It is good to test the serial
+	  connection with a live system before trying to debug.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 4
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config STACK_OVERFLOW_TEST
+	bool "Turn on kernel stack overflow testing?"
+	depends on KGDB
+	default n
+	help
+	  This option enables code in the front line interrupt handlers
+	  to check for kernel stack overflow on interrupts and system
+	  calls.  This is part of the kgdb code on x86 systems.
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
--- diff/arch/x86_64/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/kernel/kgdb_stub.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,2591 @@
+/*
+ *
+ * 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, 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.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *  X86_64 changes from Andi Kleen's patch merged by Jim Houston
+ * 	(jim.houston@ccur.com).  If it works thank Andi if its broken
+ * 	blame me.
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+#include <linux/cpumask.h>
+#include <linux/bitops.h>
+#include <linux/notifier.h>
+#include <asm/kdebug.h>
+#include <asm/uaccess.h>
+#include <linux/ptrace.h>
+
+#define Dearly_printk(x...)
+int kgdb_enabled = 0;
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 400
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES (NUMREGS * sizeof(unsigned long))
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ *
+ * Could add XMM and segment registers here.
+ */
+enum regnames {_RAX,
+	       _RBX,
+	       _RCX,
+	       _RDX,
+	       _RSI,
+	       _RDI,
+	       _RBP,
+	       _RSP,
+	       _R8,
+	       _R9,
+	       _R10,
+	       _R11,
+	       _R12,
+	       _R13,
+	       _R14,
+	       _R15,
+	       _PC,
+	       _PS,
+	       NUMREGS };
+
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_tsc;
+	int errcode;
+	int vector;
+	int print_debug_info;
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define LOOKASIDE_SIZE 200	/* should be more than enough */
+#define MALLOC_MAX   200	/* Max malloc size */
+struct {
+	unsigned long rsp;
+	unsigned long array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+static int trap_cpu;
+static unsigned long OLD_esp;
+
+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		return tty_getDebugChar();
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+__asm__("fn_rtn_stub:\n\t"
+	"movq %rax,%rsp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addq $-8,%rbx\n\t"
+	"movq (%rbx), %rax\n\t"
+	"pushq %rax\n\t"
+	"cmpq %rsp,%rcx\n\t"
+	"jne  1b\n\t"
+	"popq %rax\n\t"
+	"popq %rbx\n\t"
+	"popq %rcx\n\t"
+	"iret \n\t");
+/*					     *INDENT-ON*  */
+#define gdb_i386vector	kgdb_info.vector
+#define gdb_i386errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(&regs);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static char lbuf[BUFMAX];
+static short error;
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("RAX=%016lx RBX=%016lx RCX=%016lx\n",
+		regs->rax, regs->rbx, regs->rcx);
+	printk("RDX=%016lx RSI=%016lx RDI=%016lx\n",
+		regs->rdx, regs->rsi, regs->rdi);
+	printk("RBP=%016lx PS=%016lx PC=%016lx\n",
+		regs->rbp, regs->eflags, regs->rip);
+ 	printk("R8=%016lx R9=%016lx R10=%016lx\n",
+		regs->r8, regs->r9, regs->r10);
+	printk("R11=%016lx R12=%016lx R13=%016lx\n",
+		regs->r11, regs->r12, regs->r13);
+	printk("R14=%016lx R15=%016lx RSP=%016lx\n",
+		regs->r14, regs->r15, regs->rsp);
+}
+
+#define NEW_esp fn_call_lookaside[trap_cpu].rsp
+
+static void
+regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_RAX] =  regs->rax;
+	gdb_regs[_RBX] =  regs->rbx;
+	gdb_regs[_RCX] =  regs->rcx;
+	gdb_regs[_RDX] =  regs->rdx;
+	gdb_regs[_RSI] =  regs->rsi;
+	gdb_regs[_RDI] =  regs->rdi;
+	gdb_regs[_RBP] =  regs->rbp;
+	gdb_regs[ _PS] =  regs->eflags;
+	gdb_regs[ _PC] =  regs->rip;
+	gdb_regs[ _R8] =  regs->r8;
+	gdb_regs[ _R9] =  regs->r9;
+	gdb_regs[_R10] = regs->r10;
+	gdb_regs[_R11] = regs->r11;
+	gdb_regs[_R12] = regs->r12;
+	gdb_regs[_R13] = regs->r13;
+	gdb_regs[_R14] = regs->r14;
+	gdb_regs[_R15] = regs->r15;
+	gdb_regs[_RSP] =  regs->rsp;
+
+	/* Note, as we are a debugging the kernel, we will always
+	 * trap in kernel code, this means no priviledge change,
+	 * and so the pt_regs structure is not completely valid.  In a non
+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
+	 * SS and ESP are not stacked, this means that the last 2 elements of
+	 * pt_regs is not valid (they would normally refer to the user stack)
+	 * also, using regs+1 is no good because you end up will a value that is
+	 * 2 longs (8) too high.  This used to cause stepping over functions
+	 * to fail, so my fix is to use the address of regs->esp, which
+	 * should point at the end of the stack frame.	Note I have ignored
+	 * completely exceptions that cause an error code to be stacked, such
+	 * as double fault.  Stuart Hughes, Zentropix.
+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
+
+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
+	 */
+}
+
+static void
+gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	regs->rax	=     gdb_regs[_RAX] ;
+	regs->rbx	=     gdb_regs[_RBX] ;
+	regs->rcx	=     gdb_regs[_RCX] ;
+	regs->rdx	=     gdb_regs[_RDX] ;
+	regs->rsi	=     gdb_regs[_RSI] ;
+	regs->rdi	=     gdb_regs[_RDI] ;
+	regs->rbp	=     gdb_regs[_RBP] ;
+	regs->eflags	=     gdb_regs[ _PS] ;
+	regs->rip	=     gdb_regs[ _PC] ;
+	regs->r8	=     gdb_regs[ _R8] ;
+	regs->r9	=     gdb_regs[ _R9] ;
+	regs->r10	=     gdb_regs[ _R10] ;
+	regs->r11	=     gdb_regs[ _R11] ;
+	regs->r12	=     gdb_regs[ _R12] ;
+	regs->r13	=     gdb_regs[ _R13] ;
+	regs->r14	=     gdb_regs[ _R14] ;
+	regs->r15	=     gdb_regs[ _R15] ;
+ #if 0					/* can't change these */
+	regs->rsp	=     gdb_regs[_RSP] ;
+	regs->ss	=     gdb_regs[ _SS] ;
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+}				/* gdb_regs_to_regs */
+
+int thread_list = 0;
+extern void thread_return(void);
+
+void
+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, unsigned long *gdb_regs)
+{
+	unsigned long **rbp, *rsp, *rsp0, pc;
+	int count = 0;
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(gdb_regs, regs);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task) {
+			regs_to_gdb_regs(gdb_regs,
+					 kgdb_info.cpus_waiting[i].regs);
+			gdb_regs[_RSP] =
+			    (unsigned long)&kgdb_info.cpus_waiting[i].regs->rsp;
+
+			return;
+		}
+	}
+#endif
+	memset(gdb_regs, 0, NUMREGBYTES);
+	rsp = (unsigned long *)p->thread.rsp;
+	rbp = (unsigned long **)rsp[0];
+	rsp += 2;
+	gdb_regs[_PC] =  (unsigned long)thread_return;
+	gdb_regs[_RBP] = (unsigned long)rbp;
+	gdb_regs[_RSP] = (unsigned long)rsp;
+
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with.  This code was shamelessly purloined from process.c.  It was
+ * then enhanced to provide more registers than simply the program
+ * counter.
+ */
+
+	if (!thread_list) {
+		return;
+	}
+
+	if (p->state == TASK_RUNNING)
+		return;
+	rsp0 = (unsigned long *)p->thread.rsp0;
+	if (rsp < (unsigned long *) p->thread_info || rsp > rsp0)
+		return;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	do {
+		if (*rbp < rsp || *rbp > rsp0)
+			break;
+		rbp = (unsigned long **)*rbp;
+		rsp = (unsigned long *)rbp;
+		pc = rsp[1];
+
+		if (!in_sched_functions(pc))
+			break;
+		gdb_regs[_PC] = (unsigned long)pc;
+		gdb_regs[_RSP] = (unsigned long)rsp;
+		gdb_regs[_RBP] = (unsigned long)rbp;
+	} while (count++ < 16);
+	return;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* returns nonzero if any memory access fails. */
+int mem2hex( char* mem, char* buf, int   count)
+{
+	int i;
+	unsigned char ch;
+	int ret = 0;
+
+	for (i=0;i<count;i++) {
+		ch = 0;
+		ret |= __get_user(ch, mem);
+		mem++;
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (ret) {
+		Dearly_printk("mem2hex: fault at accessing %p\n", mem);
+	}
+	return(ret);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return nonzero if any memory access fails. */
+int hex2mem( char* buf, char* mem, int count)
+{
+	int i;
+	unsigned char ch;
+	int ret = 0;
+
+	for (i=0;i<count;i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		ret |= __put_user(ch, mem);
+		mem++;
+	}
+	if (ret) {
+		Dearly_printk("hex2mem: fault at %p\n", mem);
+	}
+	return(ret);
+}
+
+#if 0
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	/*
+	 * This code traps references to the area mapped to the kernel
+	 * stack as given by the regs and, instead, stores to the
+	 * fn_call_lookaside[cpu].array
+	 */
+	if (may_fault &&
+	    (unsigned int) addr < OLD_esp &&
+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+#endif
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToLong(char **ptr, unsigned long *value)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*value = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*value = (*value << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+		if (!cpu_online(pid - PID_MAX))
+			return NULL;
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned long addr;
+} breakinfo[4] = { {enabled:0},
+		   {enabled:0},
+		   {enabled:0},
+		   {enabled:0}};
+/* *INDENT-ON*	*/
+unsigned long hw_breakpoint_status;
+void
+correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned long dr7;
+
+	asm volatile ("movq %%db7, %0\n":"=r" (dr7)
+		      :);
+	/* *INDENT-OFF*	 */
+	do {
+		unsigned long addr0, addr1, addr2, addr3;
+		asm volatile ("movq %%db0, %0\n"
+			      "movq %%db1, %1\n"
+			      "movq %%db2, %2\n"
+			      "movq %%db3, %3\n"
+			      :"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3)
+			      :);
+	} while (0);
+	/* *INDENT-ON*	*/
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movq %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movq %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movq %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movq %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movq %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+int
+in_kgdb(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int cpu;
+	if (!kgdb_enabled)
+		return 0;
+	cpu = smp_processor_id();
+	in_kgdb_called = 1;
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			return 1;
+		}
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	local_irq_restore(flags);
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	ack_APIC_irq();
+	in_kgdb(&regs);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned long dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movq %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * The ThreadExtraInfo query allows us to pass an arbitrary string
+ * for display with the "info threads" command.
+ */
+
+void
+print_extra_info(task_t *p, char *buf)
+{
+	if (!p) {
+		sprintf(buf, "Invalid thread");
+		return;
+	}
+	sprintf(buf, "0x%p %8d %4d  %c  %s",
+		   (void *)p,  p->parent->pid,
+		   task_cpu(p),
+		   (p->state == 0) ? (task_curr(p)?'R':'r') :
+		     (p->state < 0) ? 'U' :
+		     (p->state & TASK_UNINTERRUPTIBLE) ? 'D' :
+		     (p->state & TASK_STOPPED || p->ptrace & PT_PTRACED) ? 'T' :
+		     (p->state & (TASK_ZOMBIE | TASK_DEAD)) ? 'Z' :
+		     (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?',
+		   p->comm);
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+kgdb_handle_exception(int exceptionVector,
+		      int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	struct task_struct *p;
+	unsigned long addr, length;
+	unsigned long breakno, breaktype;
+	char *ptr;
+	unsigned long newPC;
+	threadref thref;
+	unsigned long threadid, tmpid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+	unsigned long gdb_regs[NUMREGS];
+	unsigned long dr6;
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	regs	(*linux_regs)
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->cs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(&regs);
+		return (0);
+	}
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	rdtscll(kgdb_info.entry_tsc);
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		int time, end_time, dum;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		rdtsc(dum, time);
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task &&
+					    in_kgdb_here_log[j]) {
+
+						int wait = 100000;
+						while (wait--) ;
+						if (!waiting_cpus[j].task &&
+						    in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+							    (struct task_struct
+							     *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				rdtsc(dum, time);
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %d cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     (int)num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&regs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+/*				       *INDENT-OFF*  */
+      __asm__("movq %0,%%db7"
+	      :	/* no output */
+	      :"r"(0UL));
+
+	asm volatile ("movq %%db6, %0\n"
+		      :"=r" (hw_breakpoint_status)
+		      :);
+
+#if 0
+/*				       *INDENT-ON*  */
+	switch (exceptionVector) {
+	case 0:		/* divide error */
+	case 1:		/* debug exception */
+	case 2:		/* NMI */
+	case 3:		/* breakpoint */
+	case 4:		/* overflow */
+	case 5:		/* bounds check */
+	case 6:		/* invalid opcode */
+	case 7:		/* device not available */
+	case 8:		/* double fault (errcode) */
+	case 10:		/* invalid TSS (errcode) */
+	case 12:		/* stack fault (errcode) */
+	case 16:		/* floating point error */
+	case 17:		/* alignment check (errcode) */
+	default:		/* any undocumented */
+		break;
+	case 11:		/* segment not present (errcode) */
+	case 13:		/* general protection (errcode) */
+	case 14:		/* page fault (special errcode) */
+	case 19:		/* cache flush denied */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			/* make valid address */
+			regs.eax = (long) &garbage_loc;
+			/* make valid address */
+			regs.edx = (long) &garbage_loc;
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&regs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+#endif
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+	kgdb_info.called_from = __builtin_return_address(0);
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+	trap_cpu = smp_processor_id();
+	OLD_esp = NEW_esp = (unsigned long) (&linux_regs->rsp);
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	    remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, &regs, gdb_regs);
+			mem2hex((char *) gdb_regs,
+				remcomOutBuffer, NUMREGBYTES);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).
+				 */
+				unsigned long regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(gdb_regs, &regs);
+				if ((!usethread || usethread == current) &&
+				    hexToLong(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					if (regno >= NUMREGS)
+						break;
+					hex2mem(ptr, (char *) &gdb_regs[regno],
+						8);
+					gdb_regs_to_regs(gdb_regs, &regs);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToLong(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				if (mem2hex((char *) addr,
+					remcomOutBuffer, length)) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToLong(&ptr, &length)) && (*(ptr++) == ':')) {
+				if (hex2mem(ptr, (char *) addr, length)) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				} else {
+					strcpy(remcomOutBuffer, "OK");
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%lx\n", addr);
+
+				regs.rip = addr;
+			}
+
+			newPC = regs.rip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&regs);
+			}
+			asm volatile ("movq %%db6, %0\n":"=r" (dr6)
+				      :);
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno) &&
+					    (breakinfo[breakno].type == 0)) {
+						/* Set restore flag */
+						regs.eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			asm volatile ("movq %0, %%db6\n"::"r" (0UL));
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				/* If start flag set start at 0. */
+				if (remcomInBuffer[2] == '1')
+					threadid = 0;
+				else
+					threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':
+				ptr = &remcomInBuffer[0];
+				if (strncmp(ptr, "qThreadExtraInfo,",
+					strlen("qThreadExtraInfo,")) == 0) {
+					ptr += strlen("qThreadExtraInfo,");
+					hexToLong(&ptr, &tmpid);
+					p = getthread(tmpid);
+					print_extra_info(p, lbuf);
+					mem2hex(lbuf, remcomOutBuffer,
+						strlen(lbuf));
+				}
+				break;
+#if 0
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToLong(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+#endif
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToLong(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &breakno);
+			ptr++;
+			hexToLong(&ptr, &breaktype);
+			ptr++;
+			hexToLong(&ptr, &length);
+			ptr++;
+			hexToLong(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		case 'r':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			/* triplefault	 no return from here */
+			{
+				static long no_idt[2];
+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
+				BREAKPOINT;
+			}
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+	/*
+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
+	 * will be changed if we are trying to do this.	 We handle both
+	 * adding and subtracting, thus allowing gdb to put grung on
+	 * the stack which it removes later.
+	 */
+	if (NEW_esp != OLD_esp) {
+		unsigned long *ptr = END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp)
+			ptr -= (OLD_esp - NEW_esp) / sizeof (unsigned long);
+		*--ptr = linux_regs->eflags;
+		*--ptr = linux_regs->cs;
+		*--ptr = linux_regs->rip;
+		*--ptr = linux_regs->rcx;
+		*--ptr = linux_regs->rbx;
+		*--ptr = linux_regs->rax;
+		linux_regs->rcx = NEW_esp - (sizeof (unsigned long) * 6);
+		linux_regs->rbx = (unsigned long) END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp) {
+			linux_regs->rip = (unsigned long) fn_call_stub;
+		} else {
+			linux_regs->rip = (unsigned long) fn_rtn_stub;
+			linux_regs->rax = NEW_esp;
+		}
+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
+	}
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+		if (!(ss_hold)) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		local_irq_restore(flags);
+		return (1);
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	local_irq_restore(flags);
+	return (1);
+}
+
+#undef regs
+static int kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+	struct die_args *d = ptr;
+
+	if (!kgdb_enabled || (cmd == DIE_DEBUG && user_mode(d->regs)))
+		return NOTIFY_DONE;
+	if (cmd == DIE_NMI_IPI) {
+		if (in_kgdb(d->regs))
+			return NOTIFY_BAD;
+	} else if (kgdb_handle_exception(d->trapnr, d->signr, d->err, d->regs))
+		return NOTIFY_BAD; /* skip */
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block kgdb_notifier = {
+	.notifier_call = kgdb_notify,
+	.priority = 0,
+};
+
+void set_debug_traps(void)
+{
+	static int initialized = 0;
+
+	if (!initialized) {
+		initialized = 1;
+		notifier_chain_register(&die_chain, &kgdb_notifier);
+	}
+}
+
+/*
+ * Provide the command line "gdb" initial break
+ */
+int __init kgdb_initial_break(char * str)
+{
+	if (*str == '\0'){
+		breakpoint();
+		return 1;
+	}
+	return 0;
+}
+__setup("gdb",kgdb_initial_break);
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+void breakpoint(void)
+{
+
+	set_debug_traps();
+	kgdb_enabled = 1;
+#if 0
+	/*
+	 * These calls were not enough to allow breakpoint to be
+	 * called before trap_init().  I moved the argument parsing
+	 * after trap_init() and it seems to work.
+	 */
+	set_intr_usr_gate(3,&int3); /* disable ints on trap */
+	set_intr_gate(1,&debug);
+	set_intr_gate(14,&page_fault);
+#endif
+
+        BREAKPOINT;
+}
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_i386vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	spin_lock(&ts_spin);
+	rdtscll(kgdb_and_then->at_time);
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *)(long)(((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		kgdb_enabled = 1;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/x86_64/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/lib/kgdb_serial.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,490 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b) outb_p(b,a)
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_p(info->port + UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_p(info->port + UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_p(chr, info->port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, 0);
+	outb_px(0xff, 0x080);
+	scratch2 = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_p(port + UART_LCR);
+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(port + UART_LCR, 0);
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_p(port + UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_p(port + UART_MCR);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
+	outb_px(port + UART_MCR, scratch);
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	int port = info->port;
+
+	(void) inb_p(port + UART_RX);
+	outb_px(port + UART_IER, 0);
+
+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_p(port + UART_MSR);
+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(port + UART_MCR, info->MCR);
+
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr, dum, time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	rdtsc(dum, time);
+	end_time = time + 2;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		rdtsc(dum, time);
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	set_debug_traps();
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+#define kgdb_mem_init_done()    (1)
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info->port + UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+module_init(kgdb_enable_ints);
--- diff/drivers/char/hpet.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/hpet.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,1118 @@
+/*
+ * Intel & MS High Precision Event Timer Implementation.
+ * Contributors:
+ *	Venki Pallipadi
+ * 	Bob Picco
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/major.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/sysctl.h>
+#include <linux/wait.h>
+#include <linux/bcd.h>
+#include <linux/seq_file.h>
+
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/div64.h>
+
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <linux/hpet.h>
+
+/*
+ * The High Precision Event Timer driver.
+ * This driver is closely modelled after the rtc.c driver.
+ * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm
+ */
+#define	HPET_USER_FREQ	(64)
+#define	HPET_DRIFT	(500)
+
+static u32 hpet_ntimer, hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
+static char hpetname[] = "hpet/XX";
+
+/* A lock for concurrent access by app and isr hpet activity. */
+static spinlock_t hpet_lock = SPIN_LOCK_UNLOCKED;
+/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
+static spinlock_t hpet_task_lock = SPIN_LOCK_UNLOCKED;
+
+struct hpet_dev {
+	struct hpets *hd_hpets;
+	struct hpet *hd_hpet;
+	struct hpet_timer *hd_timer;
+	unsigned long hd_ireqfreq;
+	unsigned long hd_irqdata;
+	wait_queue_head_t hd_waitqueue;
+	struct fasync_struct *hd_async_queue;
+	struct hpet_task *hd_task;
+	unsigned int hd_flags;
+	unsigned int hd_irq;
+	unsigned int hd_hdwirq;
+	int hd_minor;
+};
+
+struct hpets {
+	struct hpets *hp_next;
+	struct hpet *hp_hpet;
+	unsigned long hp_period;
+	unsigned long hp_delta;
+	unsigned int hp_ntimer;
+	unsigned int hp_which;
+	struct hpet_dev hp_dev[1];
+};
+
+static struct hpets *hpets;
+
+#define	HPET_OPEN		0x0001
+#define	HPET_IE			0x0002	/* interrupt enabled */
+#define	HPET_PERIODIC		0x0004
+
+#if BITS_PER_LONG == 64
+#define	write_counter(V, MC)	writeq(V, MC)
+#define	read_counter(MC)	readq(MC)
+#else
+#define	write_counter(V, MC) 	writel(V, MC)
+#define	read_counter(MC)	readl(MC)
+#endif
+
+static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+	struct hpet_dev *devp;
+	unsigned long isr;
+
+	devp = data;
+
+	spin_lock(&hpet_lock);
+	devp->hd_irqdata++;
+
+	/*
+	 * For non-periodic timers, increment the accumulator.
+	 * This has the effect of treating non-periodic like periodic.
+	 */
+	if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) {
+		unsigned long m, t;
+
+		t = devp->hd_ireqfreq;
+		m = read_counter(&devp->hd_hpet->hpet_mc);
+		write_counter(t + m + devp->hd_hpets->hp_delta,
+			      &devp->hd_timer->hpet_compare);
+	}
+
+	isr = (1 << (devp - devp->hd_hpets->hp_dev));
+	writeq(isr, &devp->hd_hpet->hpet_isr);
+	spin_unlock(&hpet_lock);
+
+	spin_lock(&hpet_task_lock);
+	if (devp->hd_task)
+		devp->hd_task->ht_func(devp->hd_task->ht_data);
+	spin_unlock(&hpet_task_lock);
+
+	wake_up_interruptible(&devp->hd_waitqueue);
+
+	kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN);
+
+	return IRQ_HANDLED;
+}
+
+static struct hpet_dev *hpet_minor_to_dev(int minor)
+{
+	struct hpets *hpetp;
+	int i;
+
+	for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+		for (i = 0; i < hpetp->hp_ntimer; i++)
+			if (hpetp->hp_dev[i].hd_minor == minor)
+				return &hpetp->hp_dev[i];
+	return 0;
+}
+
+static int hpet_open(struct inode *inode, struct file *file)
+{
+	struct hpet_dev *devp;
+
+	devp = hpet_minor_to_dev(MINOR(inode->i_rdev));
+
+	if (!devp)
+		return -ENODEV;
+
+	spin_lock_irq(&hpet_lock);
+	if (devp->hd_flags & HPET_OPEN || devp->hd_task) {
+		spin_unlock_irq(&hpet_lock);
+		return -EBUSY;
+	}
+
+	file->private_data = devp;
+	devp->hd_irqdata = 0;
+	devp->hd_flags |= HPET_OPEN;
+	spin_unlock_irq(&hpet_lock);
+
+	return 0;
+}
+
+static ssize_t
+hpet_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t retval;
+	struct hpet_dev *devp;
+
+	devp = file->private_data;
+	if (!devp->hd_ireqfreq)
+		return -EIO;
+
+	if (count < sizeof(unsigned long))
+		return -EINVAL;
+
+	add_wait_queue(&devp->hd_waitqueue, &wait);
+
+	do {
+		__set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irq(&hpet_lock);
+		data = devp->hd_irqdata;
+		devp->hd_irqdata = 0;
+		spin_unlock_irq(&hpet_lock);
+
+		if (data)
+			break;
+		else if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		} else if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+
+		schedule();
+
+	} while (1);
+
+	retval = put_user(data, (unsigned long *)buf);
+	if (!retval)
+		retval = sizeof(unsigned long);
+      out:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&devp->hd_waitqueue, &wait);
+
+	return retval;
+}
+
+static unsigned int hpet_poll(struct file *file, poll_table * wait)
+{
+	unsigned long v;
+	struct hpet_dev *devp;
+
+	devp = file->private_data;
+
+	if (!devp->hd_ireqfreq)
+		return 0;
+
+	poll_wait(file, &devp->hd_waitqueue, wait);
+
+	spin_lock_irq(&hpet_lock);
+	v = devp->hd_irqdata;
+	spin_unlock_irq(&hpet_lock);
+
+	if (v != 0)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
+{
+#ifdef	CONFIG_HPET_NOMMAP
+	return -ENOSYS;
+#else
+	struct hpet_dev *devp;
+	unsigned long addr;
+
+	if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
+		return -EINVAL;
+
+	if (vma->vm_flags & VM_WRITE)
+		return -EPERM;
+
+	devp = file->private_data;
+	addr = (unsigned long)devp->hd_hpet;
+
+	if (addr & (PAGE_SIZE - 1))
+		return -ENOSYS;
+
+	vma->vm_flags |= VM_IO;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	addr = __pa(addr);
+
+	if (remap_page_range
+	    (vma, vma->vm_start, addr, PAGE_SIZE, vma->vm_page_prot)) {
+		printk(KERN_ERR "remap_page_range failed in hpet.c\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+#endif
+}
+
+static int hpet_fasync(int fd, struct file *file, int on)
+{
+	struct hpet_dev *devp;
+
+	devp = file->private_data;
+
+	if (fasync_helper(fd, file, on, &devp->hd_async_queue) >= 0)
+		return 0;
+	else
+		return -EIO;
+}
+
+static int hpet_release(struct inode *inode, struct file *file)
+{
+	struct hpet_dev *devp;
+	struct hpet_timer *timer;
+	int irq = 0;
+
+	devp = file->private_data;
+	timer = devp->hd_timer;
+
+	spin_lock_irq(&hpet_lock);
+
+	writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
+	       &timer->hpet_config);
+
+	irq = devp->hd_irq;
+	devp->hd_irq = 0;
+
+	devp->hd_ireqfreq = 0;
+
+	if (devp->hd_flags & HPET_PERIODIC
+	    && readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) {
+		unsigned long v;
+
+		v = readq(&timer->hpet_config);
+		v ^= Tn_TYPE_CNF_MASK;
+		writeq(v, &timer->hpet_config);
+	}
+
+	devp->hd_flags &= ~(HPET_OPEN | HPET_IE | HPET_PERIODIC);
+	spin_unlock_irq(&hpet_lock);
+
+	if (irq)
+		free_irq(irq, devp);
+
+	if (file->f_flags & FASYNC)
+		hpet_fasync(-1, file, 0);
+
+	file->private_data = 0;
+	return 0;
+}
+
+static int hpet_ioctl_common(struct hpet_dev *, int, unsigned long, int);
+
+static int
+hpet_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	   unsigned long arg)
+{
+	struct hpet_dev *devp;
+
+	devp = file->private_data;
+	return hpet_ioctl_common(devp, cmd, arg, 0);
+}
+
+static int hpet_ioctl_ieon(struct hpet_dev *devp)
+{
+	struct hpet_timer *timer;
+	struct hpet *hpet;
+	struct hpets *hpetp;
+	int irq;
+	unsigned long g, v, t, m;
+	unsigned long flags, isr;
+
+	timer = devp->hd_timer;
+	hpet = devp->hd_hpet;
+	hpetp = devp->hd_hpets;
+
+	v = readq(&timer->hpet_config);
+	spin_lock_irq(&hpet_lock);
+
+	if (devp->hd_flags & HPET_IE) {
+		spin_unlock_irq(&hpet_lock);
+		return -EBUSY;
+	}
+
+	devp->hd_flags |= HPET_IE;
+	spin_unlock_irq(&hpet_lock);
+
+	t = readq(&timer->hpet_config);
+	irq = devp->hd_hdwirq;
+
+	if (irq) {
+		char name[7];
+
+		sprintf(name, "hpet%d", (int)(devp - hpetp->hp_dev));
+
+		if (request_irq
+		    (irq, hpet_interrupt, SA_INTERRUPT, name, (void *)devp)) {
+			printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
+			irq = 0;
+		}
+	}
+
+	if (irq == 0) {
+		spin_lock_irq(&hpet_lock);
+		devp->hd_flags ^= HPET_IE;
+		spin_unlock_irq(&hpet_lock);
+		return -EIO;
+	}
+
+	devp->hd_irq = irq;
+	t = devp->hd_ireqfreq;
+	v = readq(&timer->hpet_config);
+	g = v | Tn_INT_ENB_CNF_MASK;
+
+	if (devp->hd_flags & HPET_PERIODIC) {
+		write_counter(t, &timer->hpet_compare);
+		g |= Tn_TYPE_CNF_MASK;
+		v |= Tn_TYPE_CNF_MASK;
+		writeq(v, &timer->hpet_config);
+		v |= Tn_VAL_SET_CNF_MASK;
+		writeq(v, &timer->hpet_config);
+		local_irq_save(flags);
+		m = read_counter(&hpet->hpet_mc);
+		write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+	} else {
+		local_irq_save(flags);
+		m = read_counter(&hpet->hpet_mc);
+		write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+	}
+
+	isr = (1 << (devp - hpets->hp_dev));
+	writeq(isr, &hpet->hpet_isr);
+	writeq(g, &timer->hpet_config);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static inline unsigned long hpet_time_div(unsigned long dis)
+{
+	unsigned long long m = 1000000000000000ULL;
+
+	do_div(m, dis);
+
+	return (unsigned long)m;
+}
+
+static int
+hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
+{
+	struct hpet_timer *timer;
+	struct hpet *hpet;
+	struct hpets *hpetp;
+	int err;
+	unsigned long v;
+
+	switch (cmd) {
+	case HPET_IE_OFF:
+	case HPET_INFO:
+	case HPET_EPI:
+	case HPET_DPI:
+	case HPET_IRQFREQ:
+		timer = devp->hd_timer;
+		hpet = devp->hd_hpet;
+		hpetp = devp->hd_hpets;
+		break;
+	case HPET_IE_ON:
+		return hpet_ioctl_ieon(devp);
+	default:
+		return -EINVAL;
+	}
+
+	err = 0;
+
+	switch (cmd) {
+	case HPET_IE_OFF:
+		if ((devp->hd_flags & HPET_IE) == 0)
+			break;
+		v = readq(&timer->hpet_config);
+		v &= ~Tn_INT_ENB_CNF_MASK;
+		writeq(v, &timer->hpet_config);
+		if (devp->hd_irq) {
+			free_irq(devp->hd_irq, devp);
+			devp->hd_irq = 0;
+		}
+		devp->hd_flags ^= HPET_IE;
+		break;
+	case HPET_INFO:
+		{
+			struct hpet_info info;
+
+			info.hi_ireqfreq = hpet_time_div(hpetp->hp_period *
+							 devp->hd_ireqfreq);
+			info.hi_flags =
+			    readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
+			if (copy_to_user((void *)arg, &info, sizeof(info)))
+				err = -EFAULT;
+			break;
+		}
+	case HPET_EPI:
+		v = readq(&timer->hpet_config);
+		if ((v & Tn_PER_INT_CAP_MASK) == 0) {
+			err = -ENXIO;
+			break;
+		}
+		devp->hd_flags |= HPET_PERIODIC;
+		break;
+	case HPET_DPI:
+		v = readq(&timer->hpet_config);
+		if ((v & Tn_PER_INT_CAP_MASK) == 0) {
+			err = -ENXIO;
+			break;
+		}
+		if (devp->hd_flags & HPET_PERIODIC &&
+		    readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) {
+			v = readq(&timer->hpet_config);
+			v ^= Tn_TYPE_CNF_MASK;
+			writeq(v, &timer->hpet_config);
+		}
+		devp->hd_flags &= ~HPET_PERIODIC;
+		break;
+	case HPET_IRQFREQ:
+		if (!kernel && (arg > hpet_max_freq) &&
+		    !capable(CAP_SYS_RESOURCE)) {
+			err = -EACCES;
+			break;
+		}
+
+		if (arg & (arg - 1)) {
+			err = -EINVAL;
+			break;
+		}
+
+		devp->hd_ireqfreq = hpet_time_div(hpetp->hp_period * arg);
+	}
+
+	return err;
+}
+
+static struct file_operations hpet_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = hpet_read,
+	.poll = hpet_poll,
+	.ioctl = hpet_ioctl,
+	.open = hpet_open,
+	.release = hpet_release,
+	.fasync = hpet_fasync,
+	.mmap = hpet_mmap,
+};
+
+EXPORT_SYMBOL(hpet_alloc);
+EXPORT_SYMBOL(hpet_register);
+EXPORT_SYMBOL(hpet_unregister);
+EXPORT_SYMBOL(hpet_control);
+
+int hpet_register(struct hpet_task *tp, int periodic)
+{
+	unsigned int i;
+	u64 mask;
+	struct hpet_timer *timer;
+	struct hpet_dev *devp;
+	struct hpets *hpetp;
+
+	switch (periodic) {
+	case 1:
+		mask = Tn_PER_INT_CAP_MASK;
+		break;
+	case 0:
+		mask = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irq(&hpet_task_lock);
+	spin_lock(&hpet_lock);
+
+	for (devp = 0, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
+		for (timer = hpetp->hp_hpet->hpet_timers, i = 0;
+		     i < hpetp->hp_ntimer; i++, timer++) {
+			if ((readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK)
+			    != mask)
+				continue;
+
+			devp = &hpetp->hp_dev[i];
+
+			if (devp->hd_flags & HPET_OPEN || devp->hd_task) {
+				devp = 0;
+				continue;
+			}
+
+			tp->ht_opaque = devp;
+			devp->hd_task = tp;
+			break;
+		}
+
+	spin_unlock(&hpet_lock);
+	spin_unlock_irq(&hpet_task_lock);
+
+	if (tp->ht_opaque)
+		return 0;
+	else
+		return -EBUSY;
+}
+
+static inline int hpet_tpcheck(struct hpet_task *tp)
+{
+	struct hpet_dev *devp;
+	struct hpets *hpetp;
+
+	devp = tp->ht_opaque;
+
+	if (!devp)
+		return -ENXIO;
+
+	for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+		if (devp >= hpetp->hp_dev
+		    && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
+		    && devp->hd_hpet == hpetp->hp_hpet)
+			return 0;
+
+	return -ENXIO;
+}
+
+int hpet_unregister(struct hpet_task *tp)
+{
+	struct hpet_dev *devp;
+	struct hpet_timer *timer;
+	int err;
+
+	if ((err = hpet_tpcheck(tp)))
+		return err;
+
+	spin_lock_irq(&hpet_task_lock);
+	spin_lock(&hpet_lock);
+
+	devp = tp->ht_opaque;
+	if (devp->hd_task != tp) {
+		spin_unlock(&hpet_lock);
+		spin_unlock_irq(&hpet_task_lock);
+		return -ENXIO;
+	}
+
+	timer = devp->hd_timer;
+	writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
+	       &timer->hpet_config);
+	devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
+	devp->hd_task = 0;
+	spin_unlock(&hpet_lock);
+	spin_unlock_irq(&hpet_task_lock);
+
+	return 0;
+}
+
+int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
+{
+	struct hpet_dev *devp;
+	int err;
+
+	if ((err = hpet_tpcheck(tp)))
+		return err;
+
+	spin_lock_irq(&hpet_lock);
+	devp = tp->ht_opaque;
+	if (devp->hd_task != tp) {
+		spin_unlock_irq(&hpet_lock);
+		return -ENXIO;
+	}
+	spin_unlock_irq(&hpet_lock);
+	return hpet_ioctl_common(devp, cmd, arg, 1);
+}
+
+#ifdef	CONFIG_TIME_INTERPOLATION
+
+static unsigned long hpet_offset, last_wall_hpet;
+static long hpet_nsecs_per_cycle, hpet_cycles_per_sec;
+
+static unsigned long hpet_getoffset(void)
+{
+	return hpet_offset + (read_counter(&hpets->hp_hpet->hpet_mc) -
+			      last_wall_hpet) * hpet_nsecs_per_cycle;
+}
+
+static void hpet_update(long delta)
+{
+	unsigned long mc;
+	unsigned long offset;
+
+	mc = read_counter(&hpets->hp_hpet->hpet_mc);
+	offset = hpet_offset + (mc - last_wall_hpet) * hpet_nsecs_per_cycle;
+
+	if (delta < 0 || (unsigned long)delta < offset)
+		hpet_offset = offset - delta;
+	else
+		hpet_offset = 0;
+	last_wall_hpet = mc;
+}
+
+static void hpet_reset(void)
+{
+	hpet_offset = 0;
+	last_wall_hpet = read_counter(&hpets->hp_hpet->hpet_mc);
+}
+
+static struct time_interpolator hpet_interpolator = {
+	.get_offset = hpet_getoffset,
+	.update = hpet_update,
+	.reset = hpet_reset
+};
+
+#endif
+
+static ctl_table hpet_table[] = {
+	{
+	 .ctl_name = 1,
+	 .procname = "max-user-freq",
+	 .data = &hpet_max_freq,
+	 .maxlen = sizeof(int),
+	 .mode = 0644,
+	 .proc_handler = &proc_dointvec,
+	 },
+	{.ctl_name = 0}
+};
+
+static ctl_table hpet_root[] = {
+	{
+	 .ctl_name = 1,
+	 .procname = "hpet",
+	 .maxlen = 0,
+	 .mode = 0555,
+	 .child = hpet_table,
+	 },
+	{.ctl_name = 0}
+};
+
+static ctl_table dev_root[] = {
+	{
+	 .ctl_name = CTL_DEV,
+	 .procname = "dev",
+	 .maxlen = 0,
+	 .mode = 0555,
+	 .child = hpet_root,
+	 },
+	{.ctl_name = 0}
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void *hpet_start(struct seq_file *s, loff_t * pos)
+{
+	struct hpets *hpetp;
+	loff_t n;
+
+	for (n = *pos, hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+		if (!n--)
+			return hpetp;
+
+	return 0;
+}
+
+static void *hpet_next(struct seq_file *s, void *v, loff_t * pos)
+{
+	struct hpets *hpetp;
+
+	hpetp = v;
+	++*pos;
+	return hpetp->hp_next;
+}
+
+static void hpet_stop(struct seq_file *s, void *v)
+{
+	return;
+}
+
+static int hpet_show(struct seq_file *s, void *v)
+{
+	struct hpets *hpetp;
+	struct hpet *hpet;
+	u64 cap, vendor, period;
+
+	hpetp = v;
+	hpet = hpetp->hp_hpet;
+
+	cap = readq(&hpet->hpet_cap);
+	period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >>
+	    HPET_COUNTER_CLK_PERIOD_SHIFT;
+	vendor = (cap & HPET_VENDOR_ID_MASK) >> HPET_VENDOR_ID_SHIFT;
+
+	seq_printf(s,
+		   "HPET%d period = %d 10**-15  vendor = 0x%x number timer = %d\n",
+		   hpetp->hp_which, (u32) period, (u32) vendor,
+		   hpetp->hp_ntimer);
+
+	return 0;
+}
+
+static struct seq_operations hpet_seq_ops = {
+	.start = hpet_start,
+	.next = hpet_next,
+	.stop = hpet_stop,
+	.show = hpet_show
+};
+
+static int hpet_proc_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &hpet_seq_ops);
+}
+
+static struct file_operations hpet_proc_fops = {
+	.open = hpet_proc_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release
+};
+
+/*
+ * Adjustment for when arming the timer with
+ * initial conditions.  That is, main counter
+ * ticks expired before interrupts are enabled.
+ */
+#define	TICK_CALIBRATE	(1000UL)
+
+static unsigned long __init hpet_calibrate(struct hpets *hpetp)
+{
+	struct hpet_timer *timer;
+	unsigned long t, m, count, i, flags, start;
+	struct hpet_dev *devp;
+	int j;
+	struct hpet *hpet;
+
+	for (timer = 0, j = 0, devp = hpetp->hp_dev; j < hpetp->hp_ntimer;
+	     j++, devp++)
+		if ((devp->hd_flags & HPET_OPEN) == 0) {
+			timer = devp->hd_timer;
+			break;
+		}
+
+	if (!timer)
+		return 0;
+
+	hpet = hpets->hp_hpet;
+	t = read_counter(&timer->hpet_compare);
+
+	i = 0;
+	count = hpet_time_div(hpetp->hp_period * TICK_CALIBRATE);
+
+	local_irq_save(flags);
+
+	start = read_counter(&hpet->hpet_mc);
+
+	do {
+		m = read_counter(&hpet->hpet_mc);
+		write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+	} while (i++, (m - start) < count);
+
+	local_irq_restore(flags);
+
+	return (m - start) / i;
+}
+
+static void __init hpet_init_chrdev(void)
+{
+	static int once;
+
+	if (!once++ && register_chrdev(HPET_MAJOR, "hpet", &hpet_fops))
+		panic("unable to to major %d for hpet device", HPET_MAJOR);
+
+	return;
+}
+
+static void __init hpet_post_platform(void)
+{
+	struct hpets *hpetp;
+	u32 i, ntimer;
+	struct hpet_dev *devp;
+
+	hpet_init_chrdev();
+
+	for (ntimer = 0, hpetp = hpets; hpetp; hpetp = hpetp->hp_next, ntimer++)
+		for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer;
+		     i++, devp++) {
+
+			if (devp->hd_flags & HPET_OPEN)
+				continue;
+
+			sprintf(&hpetname[5], "%d", ntimer);
+			devfs_mk_cdev(MKDEV(HPET_MAJOR, ntimer),
+				      S_IFCHR | S_IRUSR | S_IWUSR, hpetname);
+			init_waitqueue_head(&devp->hd_waitqueue);
+		}
+
+	return;
+}
+
+int __init hpet_alloc(struct hpet_data *hdp)
+{
+	u64 cap, mcfg;
+	struct hpet_dev *devp;
+	u32 i, ntimer;
+	struct hpets *hpetp;
+	size_t siz;
+	struct hpet *hpet;
+	static struct hpets *last __initdata = (struct hpets *)0;
+
+	/*
+	 * hpet_alloc can be called by platform dependent code.
+	 * if platform dependent code has allocated the hpet
+	 * ACPI also reports hpet, then we catch it here.
+	 */
+	for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+		if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address))
+			return 0;
+
+	siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) *
+				      sizeof(struct hpet_dev));
+
+	hpetp = kmalloc(siz, GFP_KERNEL);
+
+	if (!hpetp)
+		return -ENOMEM;
+
+	memset(hpetp, 0, siz);
+
+	hpetp->hp_which = hpet_nhpet++;
+	hpetp->hp_hpet = (struct hpet *)hdp->hd_address;
+
+	hpetp->hp_ntimer = hdp->hd_nirqs;
+
+	for (i = 0; i < hdp->hd_nirqs; i++)
+		hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i];
+
+	hpet = hpetp->hp_hpet;
+
+	cap = readq(&hpet->hpet_cap);
+
+	ntimer = ((cap & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT) + 1;
+
+	if (hpetp->hp_ntimer != ntimer) {
+		printk(KERN_WARNING "hpet: number irqs doesn't agree"
+		       " with number of timers\n");
+		kfree(hpetp);
+		return -ENODEV;
+	}
+
+	if (last)
+		last->hp_next = hpetp;
+	else
+		hpets = hpetp;
+
+	last = hpetp;
+
+	hpetp->hp_period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >>
+	    HPET_COUNTER_CLK_PERIOD_SHIFT;
+
+	mcfg = readq(&hpet->hpet_config);
+	if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
+		write_counter(0L, &hpet->hpet_mc);
+		mcfg |= HPET_ENABLE_CNF_MASK;
+		writeq(mcfg, &hpet->hpet_config);
+	}
+
+	/*
+	 * Create character devices and init wait queue.
+	 * If this is a platform call, then device initialization
+	 * occurs during startup call to hpet_init.
+	 */
+	if (hdp->hd_flags ^ HPET_DATA_PLATFORM)
+		hpet_init_chrdev();
+
+	for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer;
+	     i++, hpet_ntimer++, devp++) {
+		unsigned long v;
+		struct hpet_timer *timer;
+
+		timer = &hpet->hpet_timers[devp - hpetp->hp_dev];
+		v = readq(&timer->hpet_config);
+
+		devp->hd_hpets = hpetp;
+		devp->hd_hpet = hpet;
+		devp->hd_timer = timer;
+
+		devp->hd_minor = hpet_ntimer;
+
+		/*
+		 * If the timer was reserved by platform code,
+		 * then make timer unavailable for opens.
+		 */
+		if (hdp->hd_state & (1 << i)) {
+			devp->hd_flags = HPET_OPEN;
+			continue;
+		}
+
+		if (hdp->hd_flags & HPET_DATA_PLATFORM)
+			continue;
+
+		sprintf(&hpetname[5], "%d", hpet_ntimer);
+		devfs_mk_cdev(MKDEV(HPET_MAJOR, hpet_ntimer),
+			      S_IFCHR | S_IRUSR | S_IWUSR, hpetname);
+		init_waitqueue_head(&devp->hd_waitqueue);
+	}
+
+	hpetp->hp_delta = hpet_calibrate(hpetp);
+
+	return 0;
+}
+
+static acpi_status __init hpet_resources(struct acpi_resource *res, void *data)
+{
+	struct hpet_data *hdp;
+	acpi_status status;
+	struct acpi_resource_address64 addr;
+	struct hpets *hpetp;
+
+	hdp = data;
+
+	status = acpi_resource_to_address64(res, &addr);
+
+	if (ACPI_SUCCESS(status)) {
+		unsigned long size;
+
+		size = addr.max_address_range - addr.min_address_range + 1;
+		hdp->hd_address =
+		    (unsigned long)ioremap(addr.min_address_range, size);
+
+		for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+			if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address))
+				return -EBUSY;
+	} else if (res->id == ACPI_RSTYPE_EXT_IRQ) {
+		struct acpi_resource_ext_irq *irqp;
+		int i;
+
+		irqp = &res->data.extended_irq;
+
+		if (irqp->number_of_interrupts > 0) {
+			hdp->hd_nirqs = irqp->number_of_interrupts;
+
+			for (i = 0; i < hdp->hd_nirqs; i++)
+#ifdef	CONFIG_IA64
+				hdp->hd_irq[i] =
+				    acpi_register_irq(irqp->interrupts[i],
+						      irqp->active_high_low,
+						      irqp->edge_level);
+#else
+				hdp->hd_irq[i] = irqp->interrupts[i];
+#endif
+		}
+	}
+
+	return AE_OK;
+}
+
+static int __init hpet_acpi_add(struct acpi_device *device)
+{
+	acpi_status result;
+	struct hpet_data data;
+
+	memset(&data, 0, sizeof(data));
+
+	result =
+	    acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+				hpet_resources, &data);
+
+	if (ACPI_FAILURE(result))
+		return -ENODEV;
+
+	if (!data.hd_address || !data.hd_nirqs) {
+		printk("%s: no address or irqs in _CRS\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	return hpet_alloc(&data);
+}
+
+static int __init hpet_acpi_remove(struct acpi_device *device, int type)
+{
+	return 0;
+}
+
+static struct acpi_driver hpet_acpi_driver __initdata = {
+	.name = "hpet",
+	.class = "",
+	.ids = "PNP0103",
+	.ops = {
+		.add = hpet_acpi_add,
+		.remove = hpet_acpi_remove,
+		},
+};
+
+static int __init hpet_init(void)
+{
+	struct proc_dir_entry *entry;
+
+	/*
+	 * If platform dependent code allocated hpet,
+	 * then do the rest of post boot initialization
+	 * of these hpets.
+	 */
+	if (hpets)
+		hpet_post_platform();
+
+	(void)acpi_bus_register_driver(&hpet_acpi_driver);
+
+	if (hpets) {
+		entry = create_proc_entry("driver/hpet", 0, 0);
+
+		if (entry)
+			entry->proc_fops = &hpet_proc_fops;
+
+		sysctl_header = register_sysctl_table(dev_root, 0);
+
+#ifdef	CONFIG_TIME_INTERPOLATION
+		{
+			struct hpet *hpet;
+
+			hpet = hpets->hp_hpet;
+			hpet_cycles_per_sec = hpet_time_div(hpets->hp_period);
+			hpet_interpolator.frequency = hpet_cycles_per_sec;
+			hpet_interpolator.drift = hpet_cycles_per_sec *
+			    HPET_DRIFT / 1000000;
+			hpet_nsecs_per_cycle = 1000000000 / hpet_cycles_per_sec;
+			register_time_interpolator(&hpet_interpolator);
+		}
+#endif
+		return 0;
+	} else
+		return -ENODEV;
+}
+
+static void __exit hpet_exit(void)
+{
+	acpi_bus_unregister_driver(&hpet_acpi_driver);
+
+	if (hpets) {
+		unregister_sysctl_table(sysctl_header);
+		remove_proc_entry("driver/hpet", NULL);
+	}
+
+	return;
+}
+
+module_init(hpet_init);
+module_exit(hpet_exit);
+MODULE_AUTHOR("Bob Picco <Robert.Picco@hp.com>");
+MODULE_LICENSE("GPL");
--- diff/drivers/net/kgdb_eth.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/kgdb_eth.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,132 @@
+/*
+ * Network interface GDB stub
+ *
+ * Written by San Mehat (nettwerk@biodome.org)
+ * Based upon 'gdbserial' by David Grothe (dave@gcom.com)
+ * and Scott Foehner (sfoehner@engr.sgi.com)
+ *
+ * Twiddled for 2.6 by Robert Walsh <rjwalsh@durables.org>
+ * and wangdi <wangdi@clusterfs.com>.
+ *
+ * Refactored for netpoll API by Matt Mackall <mpm@selenic.com>
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/netpoll.h>
+
+#include <asm/system.h>
+#include <asm/kgdb.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#define IN_BUF_SIZE 512 /* power of 2, please */
+#define OUT_BUF_SIZE 256
+
+static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE];
+static int in_head, in_tail, out_count;
+static atomic_t in_count;
+int kgdboe = 0; /* Default to tty mode */
+
+extern void set_debug_traps(void);
+extern void breakpoint(void);
+static void rx_hook(struct netpoll *np, int port, char *msg, int len);
+
+static struct netpoll np = {
+	.name = "kgdboe",
+	.dev_name = "eth0",
+	.rx_hook = rx_hook,
+	.local_port = 6443,
+	.remote_port = 6442,
+	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+static int configured;
+
+int eth_getDebugChar(void)
+{
+	int chr;
+
+	while (atomic_read(&in_count) == 0)
+		netpoll_poll(&np);
+
+	chr = in_buf[in_tail++];
+	in_tail &= (IN_BUF_SIZE - 1);
+	atomic_dec(&in_count);
+	return chr;
+}
+
+void eth_flushDebugChar(void)
+{
+	if(out_count && np.dev) {
+		netpoll_send_udp(&np, out_buf, out_count);
+		out_count = 0;
+	}
+}
+
+void eth_putDebugChar(int chr)
+{
+	out_buf[out_count++] = chr;
+	if(out_count == OUT_BUF_SIZE)
+		eth_flushDebugChar();
+}
+
+static void rx_hook(struct netpoll *np, int port, char *msg, int len)
+{
+	int i;
+
+	np->remote_port = port;
+
+	/* Is this gdb trying to attach? */
+	if (!netpoll_trap() && len == 8 && !strncmp(msg, "$Hc-1#09", 8))
+		kgdb_schedule_breakpoint();
+
+	for (i = 0; i < len; i++) {
+		if (msg[i] == 3)
+			kgdb_schedule_breakpoint();
+
+		if (atomic_read(&in_count) >= IN_BUF_SIZE) {
+			/* buffer overflow, clear it */
+			in_head = in_tail = 0;
+			atomic_set(&in_count, 0);
+			break;
+		}
+		in_buf[in_head++] = msg[i];
+		in_head &= (IN_BUF_SIZE - 1);
+		atomic_inc(&in_count);
+	}
+}
+
+static int option_setup(char *opt)
+{
+	configured = !netpoll_parse_options(&np, opt);
+	return 0;
+}
+__setup("kgdboe=", option_setup);
+
+static int init_kgdboe(void)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > CONFIG_NO_KGDB_CPUS) {
+		printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS);
+		return -1;
+	}
+#endif
+
+	set_debug_traps();
+
+	if(!configured || netpoll_setup(&np))
+		return 1;
+
+	kgdboe = 1;
+	printk(KERN_INFO "kgdb: debugging over ethernet enabled\n");
+
+	return 0;
+}
+
+module_init(init_kgdboe);
--- diff/drivers/net/wireless/prism54/prismcompat.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/wireless/prism54/prismcompat.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,54 @@
+/*
+ *  (C) 2004 Margit Schubert-While <margitsw@t-online.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
+ *
+ *  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
+ *
+ */
+
+/*
+ *	Compatibility header file to aid support of different kernel versions
+ */
+
+#ifdef	PRISM54_COMPAT24
+#include "prismcompat24.h"
+#else	/* PRISM54_COMPAT24 */
+
+#ifndef _PRISM_COMPAT_H
+#define _PRISM_COMPAT_H
+
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/config.h>
+#include <linux/moduleparam.h>
+#include <linux/workqueue.h>
+#include <linux/compiler.h>
+
+#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE)
+#error Firmware Loading is not configured in the kernel !
+#endif
+
+#define prism54_synchronize_irq(irq) synchronize_irq(irq)
+
+#define PRISM_DEFWAITQ(y)	DEFINE_WAIT(y)
+
+#define PRISM_PREPWAITQ(x, y)	prepare_to_wait(&(x), &(y), TASK_UNINTERRUPTIBLE)
+
+#define PRISM_ENDWAITQ(x, y)	finish_wait(&(x), &(y))
+
+#define _REQ_FW_DEV_T		struct device *
+
+#define PRISM_FW_PDEV		&priv->pdev->dev
+
+#endif				/* _PRISM_COMPAT_H */
+#endif				/* PRISM54_COMPAT24 */
--- diff/drivers/net/wireless/prism54/prismcompat24.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/wireless/prism54/prismcompat24.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,72 @@
+/*
+ *  (C) 2004 Margit Schubert-While <margitsw@t-online.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
+ *
+ *  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
+ *
+ */
+
+/*
+ *	Compatibility header file to aid support of different kernel versions
+ */
+
+#ifndef _PRISM_COMPAT_H
+#define _PRISM_COMPAT_H
+
+#include <linux/firmware.h>
+#include <linux/config.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/compiler.h>
+#include <asm/uaccess.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25)
+#define module_param(x, y, z)	MODULE_PARM(x, "i")
+#else
+#include <linux/moduleparam.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+#define free_netdev(x)		kfree(x)
+#define pci_name(x)		x->slot_name
+#define irqreturn_t		void
+#define IRQ_HANDLED
+#define IRQ_NONE
+#else
+#include <linux/interrupt.h>
+#endif
+
+#define work_struct		tq_struct
+#define INIT_WORK		INIT_TQUEUE
+#define schedule_work		schedule_task
+
+#define netdev_priv(x)		x->priv
+
+#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE)
+#error Firmware Loading is not configured in the kernel !
+#endif
+
+#define prism54_synchronize_irq(irq) synchronize_irq()
+
+#define PRISM_DEFWAITQ(y)	DECLARE_WAITQUEUE(y, current)
+#define PRISM_PREPWAITQ(x, y)	set_current_state(TASK_UNINTERRUPTIBLE); \
+	add_wait_queue(&(x), &(y))
+
+#define PRISM_ENDWAITQ(x, y)	remove_wait_queue(&(x), &(y)); \
+	set_current_state(TASK_RUNNING)
+
+#define _REQ_FW_DEV_T		char *
+
+#define PRISM_FW_PDEV		pci_name(priv->pdev)
+
+#endif				/* _PRISM_COMPAT_H */
--- diff/drivers/scsi/3w-9xxx.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/scsi/3w-9xxx.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,2144 @@
+/*
+   3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linuxraid@amcc.com>
+
+   Copyright (C) 2004 Applied Micro Circuits Corporation.
+
+   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; version 2 of the License.
+
+   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.
+
+   NO WARRANTY
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+   solely responsible for determining the appropriateness of using and
+   distributing the Program and assumes all risks associated with its
+   exercise of rights under this Agreement, including but not limited to
+   the risks and costs of program errors, damage to or loss of data,
+   programs or equipment, and unavailability or interruption of operations.
+
+   DISCLAIMER OF LIABILITY
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+   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
+
+   Bugs/Comments/Suggestions should be mailed to:
+   linuxraid@amcc.com
+
+   For more information, goto:
+   http://www.amcc.com
+
+   Note: This version of the driver does not contain a bundled firmware
+         image.
+
+   History
+   -------
+   2.26.00.005 - Initial release.
+   2.26.00.006 - Remove TW_WRITEL macro, replace with writeq().
+   2.26.00.007 - Skip lun and channel probes.
+   2.26.00.008 - Fix bug in attention/command interrupt handling.
+   2.26.00.009 - Convert driver to pci_driver format.
+                 Remove proc interface, add sysfs attributes.
+                 Return SCSI_MLQUEUE_HOST_BUSY when card status is busy.
+*/
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
+#include "3w-9xxx.h"
+
+/* Globals */
+char *twa_driver_version="2.26.00.009";
+TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
+static unsigned int twa_device_extension_count;
+static int twa_major = -1;
+extern struct timezone sys_tz;
+static int cmds_per_lun;
+
+/* Module parameters */
+MODULE_AUTHOR ("AMCC");
+MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
+MODULE_LICENSE("GPL");
+module_param(cmds_per_lun, int, 0);
+MODULE_PARM_DESC(cmds_per_lun, "Maximum commands per LUN");
+
+/* Function prototypes */
+static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id);
+static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int check_reset);
+static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
+static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
+static char *twa_aen_severity_lookup(unsigned char severity_code);
+static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
+static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
+static int twa_check_bits(u32 status_reg_value);
+static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed);
+static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int twa_chrdev_open(struct inode *inode, struct file *file);
+static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
+static int twa_empty_response_queue(TW_Device_Extension *tw_dev);
+static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
+static void twa_free_device_extension(TW_Device_Extension *tw_dev);
+static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
+static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes);
+static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id);
+static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+ 			      u32 set_features, unsigned short current_fw_srl,
+			      unsigned short current_fw_arch_id,
+			      unsigned short current_fw_branch,
+			      unsigned short current_fw_build,
+			      unsigned short *fw_on_ctlr_srl,
+			      unsigned short *fw_on_ctlr_arch_id,
+			      unsigned short *fw_on_ctlr_branch,
+			      unsigned short *fw_on_ctlr_build,
+			      u32 *init_connect_result);
+static int twa_initialize_device_extension(TW_Device_Extension *tw_dev);
+static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
+static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id);
+static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id);
+static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
+static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds);
+static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
+static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
+static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
+static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]);
+static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id);
+static int twa_scsi_eh_abort(struct scsi_cmnd *SCpnt);
+static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt);
+static int twa_scsi_queue(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *));
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg);
+static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
+static int twa_setup_irq(TW_Device_Extension *tw_dev);
+static int twa_slave_configure(struct scsi_device *SDptr);
+static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
+static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
+
+/* Functions */
+
+/* Show some statistics about the card */
+static ssize_t twa_show_stats(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(class_dev);
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+	unsigned long flags = 0;
+	ssize_t len;
+
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
+	len = snprintf(buf, PAGE_SIZE, "Driver version: %s\n"
+		       "Current commands posted:   %4d\n"
+		       "Max commands posted:       %4d\n"
+		       "Current pending commands:  %4d\n"
+		       "Max pending commands:      %4d\n"
+		       "Last sgl length:           %4d\n"
+		       "Max sgl length:            %4d\n"
+		       "Last sector count:         %4d\n"
+		       "Max sector count:          %4d\n"
+		       "SCSI Host Resets:          %4d\n"
+		       "SCSI Aborts/Timeouts:      %4d\n"
+		       "AEN's:                     %4d\n",
+		       twa_driver_version,
+		       tw_dev->posted_request_count,
+		       tw_dev->max_posted_request_count,
+		       tw_dev->pending_request_count,
+		       tw_dev->max_pending_request_count,
+		       tw_dev->sgl_entries,
+		       tw_dev->max_sgl_entries,
+		       tw_dev->sector_count,
+		       tw_dev->max_sector_count,
+		       tw_dev->num_resets,
+		       tw_dev->num_aborts,
+		       tw_dev->aen_count);
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+	return len;
+} /* End twa_show_stats() */
+
+/* Create sysfs 'stats' entry */
+static struct class_device_attribute twa_host_stats_attr = {
+	.attr = {
+		.name = 	"stats",
+		.mode =		S_IRUGO,
+	},
+	.show = twa_show_stats
+};
+
+/* Host attributes initializer */
+static struct class_device_attribute *twa_host_attrs[] = {
+	&twa_host_stats_attr,
+	NULL,
+};
+
+/* File operations struct for character device */
+static struct file_operations twa_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= twa_chrdev_ioctl,
+	.open		= twa_chrdev_open,
+	.release	= NULL
+};
+
+/* This function will complete an aen request from the isr */
+static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Command_Apache_Header *header;
+	unsigned short aen;
+	int retval = 1;
+
+	header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+	tw_dev->posted_request_count--;
+	aen = header->status_block.error;
+	full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+	command_packet = &full_command_packet->command.oldcommand;
+
+	/* First check for internal completion of set param for time sync */
+	if (command_packet->byte0_offset.opcode == TW_OP_SET_PARAM) {
+		/* Keep reading the queue in case there are more aen's */
+		if (twa_aen_read_queue(tw_dev, request_id))
+			goto out2;
+	        else {
+			retval = 0;
+			goto out;
+		}
+	}
+
+	switch (aen) {
+	case TW_AEN_QUEUE_EMPTY:
+		/* Quit reading the queue if this is the last one */
+		break;
+	case TW_AEN_SYNC_TIME_WITH_HOST:
+		twa_aen_sync_time(tw_dev, request_id);
+		retval = 0;
+		goto out;
+	default:
+		twa_aen_queue_event(tw_dev, header);
+
+		/* If there are more aen's, keep reading the queue */
+		if (twa_aen_read_queue(tw_dev, request_id))
+			goto out2;
+		else {
+			retval = 0;
+			goto out;
+		}
+	}
+	retval = 0;
+out2:
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	twa_free_request_id(tw_dev, request_id);
+	clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+out:
+	return retval;
+} /* End twa_aen_complete() */
+
+/* This function will drain aen queue */
+static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
+{
+	int request_id = 0;
+	char cdb[TW_MAX_CDB_LEN];
+	TW_SG_Apache sglist[1];
+	int finished = 0, count = 0;
+	TW_Command_Full *full_command_packet;
+	TW_Command_Apache_Header *header;
+	unsigned short aen;
+	int first_reset = 0, queue = 0, retval = 1;
+
+	if (no_check_reset)
+		first_reset = 0;
+	else
+		first_reset = 1;
+
+	full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+	/* Initialize cdb */
+	memset(&cdb, 0, TW_MAX_CDB_LEN);
+	cdb[0] = REQUEST_SENSE; /* opcode */
+	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+	/* Initialize sglist */
+	memset(&sglist, 0, sizeof(TW_SG_Apache));
+	sglist[0].length = TW_SECTOR_SIZE;
+	sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+	if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
+		goto out;
+	}
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	do {
+		/* Send command to the board */
+		if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense");
+			goto out;
+		}
+
+		/* Now poll for completion */
+		if (twa_poll_response(tw_dev, request_id, 30)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue");
+			tw_dev->posted_request_count--;
+			goto out;
+		}
+
+		tw_dev->posted_request_count--;
+		header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+		aen = header->status_block.error;
+		queue = 0;
+		count++;
+
+		switch (aen) {
+		case TW_AEN_QUEUE_EMPTY:
+			if (first_reset != 1)
+				goto out;
+			else
+				finished = 1;
+			break;
+		case TW_AEN_SOFT_RESET:
+			if (first_reset == 0)
+				first_reset = 1;
+			else
+				queue = 1;
+			break;
+		case TW_AEN_SYNC_TIME_WITH_HOST:
+			break;
+		default:
+			queue = 1;
+		}
+
+		/* Now queue an event info */
+		if (queue)
+			twa_aen_queue_event(tw_dev, header);
+	} while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
+
+	if (count == TW_MAX_AEN_DRAIN)
+		goto out;
+
+	retval = 0;
+out:
+	tw_dev->state[request_id] = TW_S_INITIAL;
+	return retval;
+} /* End twa_aen_drain_queue() */
+
+/* This function will queue an event */
+static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
+{
+	u32 local_time;
+	struct timeval time;
+	TW_Event *event;
+	unsigned short aen;
+	char host[16];
+
+	tw_dev->aen_count++;
+
+	/* Fill out event info */
+	event = tw_dev->event_queue[tw_dev->error_index];
+
+	/* Check for clobber */
+	host[0] = '\0';
+	if (tw_dev->host) {
+		sprintf(host, " scsi%d:", tw_dev->host->host_no);
+		if (event->retrieved == TW_AEN_NOT_RETRIEVED)
+			tw_dev->aen_clobber = 1;
+	}
+
+	aen = header->status_block.error;
+	memset(event, 0, sizeof(TW_Event));
+
+	event->severity = header->status_block.substatus_block.severity;
+	do_gettimeofday(&time);
+	local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
+	event->time_stamp_sec = local_time;
+	event->aen_code = aen;
+	event->retrieved = TW_AEN_NOT_RETRIEVED;
+	event->sequence_id = tw_dev->error_sequence_id;
+	tw_dev->error_sequence_id++;
+
+	header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
+	event->parameter_len = strlen(header->err_specific_desc);
+	memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len);
+	if (event->severity != TW_AEN_SEVERITY_DEBUG)
+		printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n", host, twa_aen_severity_lookup(header->status_block.substatus_block.severity), TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, twa_string_lookup(twa_aen_table, aen), header->err_specific_desc);
+	else
+		tw_dev->aen_count--;
+
+	if ((tw_dev->error_index + 1) == TW_Q_LENGTH)
+		tw_dev->event_queue_wrapped = 1;
+	tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
+} /* End twa_aen_queue_event() */
+
+/* This function will read the aen queue from the isr */
+static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
+{
+	char cdb[TW_MAX_CDB_LEN];
+	TW_SG_Apache sglist[1];
+	TW_Command_Full *full_command_packet;
+	int retval = 1;
+
+	full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+	/* Initialize cdb */
+	memset(&cdb, 0, TW_MAX_CDB_LEN);
+	cdb[0] = REQUEST_SENSE; /* opcode */
+	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+	/* Initialize sglist */
+	memset(&sglist, 0, sizeof(TW_SG_Apache));
+	sglist[0].length = TW_SECTOR_SIZE;
+	sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	/* Now post the command packet */
+	if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_aen_read_queue() */
+
+/* This function will look up an AEN severity string */
+static char *twa_aen_severity_lookup(unsigned char severity_code)
+{
+	char *retval = NULL;
+
+	if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
+	    (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
+		goto out;
+
+	retval = twa_aen_severity_table[severity_code];
+out:
+	return retval;
+} /* End twa_aen_severity_lookup() */
+
+/* This function will sync firmware time with the host time */
+static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
+{
+	u32 schedulertime;
+	struct timeval utc;
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Param_Apache *param;
+	u32 local_time;
+
+	/* Fill out the command packet */
+	full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	command_packet = &full_command_packet->command.oldcommand;
+	command_packet->byte0_offset.opcode = TW_OP_SET_PARAM;
+	command_packet->byte0_offset.sgl_offset = 2;
+	command_packet->request_id = request_id;
+	command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id];
+	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+	command_packet->size = TW_COMMAND_SIZE;
+	command_packet->byte6_offset.parameter_count = 1;
+
+	/* Setup the param */
+	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+	memset(param, 0, TW_SECTOR_SIZE);
+	param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */
+	param->parameter_id = 0x3; /* SchedulerTime */
+	param->parameter_size_bytes = 4;
+
+	/* Convert system time in UTC to local time seconds since last
+           Sunday 12:00AM */
+	do_gettimeofday(&utc);
+	local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
+	schedulertime = local_time - (3 * 86400);
+	schedulertime = schedulertime % 604800;
+
+	memcpy(param->data, &schedulertime, sizeof(u32));
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	/* Now post the command */
+	twa_post_command_packet(tw_dev, request_id, 1);
+} /* End twa_aen_sync_time() */
+
+/* This function will allocate memory and check if it is correctly aligned */
+static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
+{
+	int i;
+	dma_addr_t dma_handle;
+	unsigned long *cpu_addr;
+	int retval = 1;
+
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+	if (!cpu_addr) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
+		goto out;
+	}
+
+	if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
+		pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
+		goto out;
+	}
+
+	memset(cpu_addr, 0, size*TW_Q_LENGTH);
+
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		switch(which) {
+		case 0:
+			tw_dev->command_packet_phys[i] = dma_handle+(i*size);
+			tw_dev->command_packet_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+			break;
+		case 1:
+			tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
+			tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+			break;
+		}
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_allocate_memory() */
+
+/* This function will check the status register for unexpected bits */
+static int twa_check_bits(u32 status_reg_value)
+{
+	int retval = 1;
+
+	if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)
+		goto out;
+	if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)
+		goto out;
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_check_bits() */
+
+/* This function will check the srl and decide if we are compatible  */
+static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
+{
+	int retval = 1;
+	unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
+	unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
+	u32 init_connect_result = 0;
+
+	if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL, TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH, TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl, &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, &fw_on_ctlr_build, &init_connect_result)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
+		goto out;
+	}
+
+	tw_dev->working_srl = TW_CURRENT_FW_SRL;
+	tw_dev->working_branch = TW_CURRENT_FW_BRANCH;
+	tw_dev->working_build = TW_CURRENT_FW_BUILD;
+
+	/* Try base mode compatibility */
+	if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
+		if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, TW_EXTENDED_INIT_CONNECT, TW_BASE_FW_SRL, TW_9000_ARCH_ID, TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD, &fw_on_ctlr_srl, &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, &fw_on_ctlr_build, &init_connect_result)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");
+			goto out;
+		}
+		if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
+			if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
+			} else {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
+			}
+			goto out;
+		}
+		tw_dev->working_srl = TW_BASE_FW_SRL;
+		tw_dev->working_branch = TW_BASE_FW_BRANCH;
+		tw_dev->working_build = TW_BASE_FW_BUILD;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_check_srl() */
+
+/* This function handles ioctl for the character device */
+static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long timeout;
+	unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
+	dma_addr_t dma_handle;
+	int request_id = 0;
+	unsigned int sequence_id = 0;
+	unsigned char event_index, start_index;
+	TW_Ioctl_Driver_Command driver_command;
+	TW_Ioctl_Buf_Apache *tw_ioctl;
+	TW_Lock *tw_lock;
+	TW_Command_Full *full_command_packet;
+	TW_Compatibility_Info *tw_compat_info;
+	TW_Event *event;
+	struct timeval current_time;
+	u32 current_time_ms;
+	TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];
+	int retval = TW_IOCTL_ERROR_OS_EFAULT;
+
+	/* Only let one of these through at a time */
+	if (down_interruptible(&tw_dev->ioctl_sem)) {
+		retval = TW_IOCTL_ERROR_OS_EINTR;
+		goto out;
+	}
+
+	/* First copy down the driver command */
+	if (copy_from_user(&driver_command, (void *)arg, sizeof(TW_Ioctl_Driver_Command)))
+		goto out2;
+
+	/* Check data buffer size */
+	if (driver_command.buffer_length > TW_MAX_SECTORS * 512) {
+		retval = TW_IOCTL_ERROR_OS_EINVAL;
+		goto out2;
+	}
+
+	/* Hardware can only do multiple of 512 byte transfers */
+	data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
+
+	/* Now allocate ioctl buf memory */
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle);
+	if (!cpu_addr) {
+		retval = TW_IOCTL_ERROR_OS_ENOMEM;
+		goto out2;
+	}
+
+	tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
+
+	/* Now copy down the entire ioctl */
+	if (copy_from_user(tw_ioctl, (void *)arg, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
+		goto out3;
+
+	/* See which ioctl we are doing */
+	switch (cmd) {
+	case TW_IOCTL_FIRMWARE_PASS_THROUGH:
+		spin_lock_irqsave(tw_dev->host->host_lock, flags);
+		twa_get_request_id(tw_dev, &request_id);
+
+		/* Flag internal command */
+		tw_dev->srb[request_id] = 0;
+
+		/* Flag chrdev ioctl */
+		tw_dev->chrdev_request_id = request_id;
+
+		full_command_packet = &tw_ioctl->firmware_command;
+
+		/* Load request id and sglist for both command types */
+		twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
+
+		memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
+
+		/* Now post the command packet to the controller */
+		twa_post_command_packet(tw_dev, request_id, 1);
+		spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+		timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
+
+		/* Now wait for command to complete */
+		timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+
+		/* Check if we timed out, got a signal, or didn't get
+                   an interrupt */
+		if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
+			/* Now we need to reset the board */
+			if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) {
+				retval = timeout;
+			} else {
+				printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0xc, cmd);
+				retval = TW_IOCTL_ERROR_OS_EIO;
+			}
+			spin_lock_irqsave(tw_dev->host->host_lock, flags);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			twa_free_request_id(tw_dev, request_id);
+			tw_dev->posted_request_count--;
+			twa_reset_device_extension(tw_dev);
+			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+			goto out3;
+		}
+
+		/* Now copy in the command packet response */
+		memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
+
+		/* Now complete the io */
+		spin_lock_irqsave(tw_dev->host->host_lock, flags);
+		tw_dev->posted_request_count--;
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		twa_free_request_id(tw_dev, request_id);
+		spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+		break;
+	case TW_IOCTL_GET_COMPATIBILITY_INFO:
+		tw_ioctl->driver_command.status = 0;
+		/* Copy compatiblity struct into ioctl data buffer */
+		tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
+		strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version));
+		tw_compat_info->working_srl = tw_dev->working_srl;
+		tw_compat_info->working_branch = tw_dev->working_branch;
+		tw_compat_info->working_build = tw_dev->working_build;
+		break;
+	case TW_IOCTL_GET_LAST_EVENT:
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			} else
+				tw_ioctl->driver_command.status = 0;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			tw_ioctl->driver_command.status = 0;
+		}
+		event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_FIRST_EVENT:
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			} else
+				tw_ioctl->driver_command.status = 0;
+			event_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			tw_ioctl->driver_command.status = 0;
+			event_index = 0;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_NEXT_EVENT:
+		event = (TW_Event *)tw_ioctl->data_buffer;
+		sequence_id = event->sequence_id;
+		tw_ioctl->driver_command.status = 0;
+
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			}
+			start_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			start_index = 0;
+		}
+		event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;
+
+		if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {
+			if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
+				tw_dev->aen_clobber = 1;
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+			break;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_PREVIOUS_EVENT:
+		event = (TW_Event *)tw_ioctl->data_buffer;
+		sequence_id = event->sequence_id;
+		tw_ioctl->driver_command.status = 0;
+
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			}
+			start_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			start_index = 0;
+		}
+		event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH;
+
+		if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) {
+			if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
+				tw_dev->aen_clobber = 1;
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+			break;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_LOCK:
+		tw_lock = (TW_Lock *)tw_ioctl->data_buffer;
+		do_gettimeofday(&current_time);
+		current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);
+
+		if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {
+			tw_dev->ioctl_sem_lock = 1;
+			tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;
+			tw_ioctl->driver_command.status = 0;
+			tw_lock->time_remaining_msec = tw_lock->timeout_msec;
+		} else {
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;
+			tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;
+		}
+		break;
+	case TW_IOCTL_RELEASE_LOCK:
+		if (tw_dev->ioctl_sem_lock == 1) {
+			tw_dev->ioctl_sem_lock = 0;
+			tw_ioctl->driver_command.status = 0;
+		} else {
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;
+		}
+		break;
+	default:
+		retval = TW_IOCTL_ERROR_OS_ENOTTY;
+		goto out3;
+	}
+
+	/* Now copy the entire response to userspace */
+	if (copy_to_user((void *)arg, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
+		retval = 0;
+out3:
+	/* Now free ioctl buf memory */
+	pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+out2:
+	up(&tw_dev->ioctl_sem);
+out:
+	return retval;
+} /* End twa_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int twa_chrdev_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor_number;
+	int retval = TW_IOCTL_ERROR_OS_ENODEV;
+
+	minor_number = iminor(inode);
+	if (minor_number >= twa_device_extension_count)
+		goto out;
+	retval = 0;
+out:
+	return retval;
+} /* End twa_chrdev_open() */
+
+/* This function will print readable messages from status register errors */
+static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
+{
+	int retval = 1;
+
+	/* Check for various error conditions and handle them appropriately */
+	if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");
+		writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_PCI_ABORT) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");
+		writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
+		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
+	}
+
+	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
+		writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing");
+		writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
+		if (tw_dev->reset_print == 0) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
+			tw_dev->reset_print = 1;
+		}
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_decode_bits() */
+
+/* This function will empty the response queue */
+static int twa_empty_response_queue(TW_Device_Extension *tw_dev)
+{
+	u32 status_reg_value, response_que_value;
+	int count = 0, retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+	while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
+		response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+		count++;
+	}
+	if (count == TW_MAX_RESPONSE_DRAIN)
+		goto out;
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_empty_response_queue() */
+
+/* This function passes sense keys from firmware to scsi layer */
+static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
+{
+	TW_Command_Full *full_command_packet;
+	unsigned short error;
+	int retval = 1;
+
+	full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+	/* Don't print error for Logical unit not supported during rollcall */
+	error = full_command_packet->header.status_block.error;
+	if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
+		if (print_host)
+			printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", tw_dev->host->host_no, TW_MESSAGE_SOURCE_CONTROLLER_ERROR, full_command_packet->header.status_block.error, twa_string_lookup(twa_error_table, full_command_packet->header.status_block.error), full_command_packet->header.err_specific_desc);
+		else
+			printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n", TW_MESSAGE_SOURCE_CONTROLLER_ERROR, full_command_packet->header.status_block.error, twa_string_lookup(twa_error_table, full_command_packet->header.status_block.error), full_command_packet->header.err_specific_desc);
+	}
+
+	if (copy_sense) {
+		memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);
+		tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
+		retval = TW_ISR_DONT_RESULT;
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_fill_sense() */
+
+/* This function will free up device extension resources */
+static void twa_free_device_extension(TW_Device_Extension *tw_dev)
+{
+	if (tw_dev->command_packet_virt[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command_Full)*TW_Q_LENGTH, tw_dev->command_packet_virt[0], tw_dev->command_packet_phys[0]);
+
+	if (tw_dev->generic_buffer_virt[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, TW_SECTOR_SIZE*TW_Q_LENGTH, tw_dev->generic_buffer_virt[0], tw_dev->generic_buffer_phys[0]);
+
+	if (tw_dev->event_queue[0])
+		kfree(tw_dev->event_queue[0]);
+} /* End twa_free_device_extension() */
+
+/* This function will free a request id */
+static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id)
+{
+	tw_dev->free_queue[tw_dev->free_tail] = request_id;
+	tw_dev->state[request_id] = TW_S_FINISHED;
+	tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
+} /* End twa_free_request_id() */
+
+/* This function will get parameter table entires from the firmware */
+static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Param_Apache *param;
+	unsigned long param_value;
+	void *retval = NULL;
+
+	/* Setup the command packet */
+	full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	command_packet = &full_command_packet->command.oldcommand;
+
+	command_packet->byte0_offset.opcode      = TW_OP_GET_PARAM;
+	command_packet->byte0_offset.sgl_offset  = 2;
+	command_packet->size              = TW_COMMAND_SIZE;
+	command_packet->request_id        = request_id;
+	command_packet->byte6_offset.block_count = 1;
+
+	/* Now setup the param */
+	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+	memset(param, 0, TW_SECTOR_SIZE);
+	param->table_id = table_id | 0x8000;
+	param->parameter_id = parameter_id;
+	param->parameter_size_bytes = parameter_size_bytes;
+	param_value = tw_dev->generic_buffer_phys[request_id];
+
+	command_packet->byte8_offset.param.sgl[0].address = param_value;
+	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+
+	/* Post the command packet to the board */
+	twa_post_command_packet(tw_dev, request_id, 1);
+
+	/* Poll for completion */
+	if (twa_poll_response(tw_dev, request_id, 30))
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")
+	else
+		retval = (void *)&(param->data[0]);
+
+	tw_dev->posted_request_count--;
+	tw_dev->state[request_id] = TW_S_INITIAL;
+
+	return retval;
+} /* End twa_get_param() */
+
+/* This function will assign an available request id */
+static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
+{
+	*request_id = tw_dev->free_queue[tw_dev->free_head];
+	tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
+	tw_dev->state[*request_id] = TW_S_STARTED;
+} /* End twa_get_request_id() */
+
+/* This function will send an initconnection command to controller */
+static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+ 			      u32 set_features, unsigned short current_fw_srl,
+			      unsigned short current_fw_arch_id,
+			      unsigned short current_fw_branch,
+			      unsigned short current_fw_build,
+			      unsigned short *fw_on_ctlr_srl,
+			      unsigned short *fw_on_ctlr_arch_id,
+			      unsigned short *fw_on_ctlr_branch,
+			      unsigned short *fw_on_ctlr_build,
+			      u32 *init_connect_result)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Initconnect *tw_initconnect;
+	int request_id = 0, retval = 1;
+
+	/* Initialize InitConnection command packet */
+	full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	full_command_packet->header.header_desc.size_header = 128;
+
+	tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
+	tw_initconnect->opcode = TW_OP_INIT_CONNECTION;
+
+	tw_initconnect->request_id = request_id;
+	tw_initconnect->message_credits = message_credits;
+	tw_initconnect->features = set_features;
+#if BITS_PER_LONG > 32
+	/* Turn on 64-bit sgl support */
+	tw_initconnect->features |= 1;
+#endif
+
+	if (set_features & TW_EXTENDED_INIT_CONNECT) {
+		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
+		tw_initconnect->fw_srl = current_fw_srl;
+		tw_initconnect->fw_arch_id = current_fw_arch_id;
+		tw_initconnect->fw_branch = current_fw_branch;
+		tw_initconnect->fw_build = current_fw_build;
+	} else
+		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
+
+	/* Send command packet to the board */
+	twa_post_command_packet(tw_dev, request_id, 1);
+
+	/* Poll for completion */
+	if (twa_poll_response(tw_dev, request_id, 30)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");
+	} else {
+		if (set_features & TW_EXTENDED_INIT_CONNECT) {
+			*fw_on_ctlr_srl = tw_initconnect->fw_srl;
+			*fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id;
+			*fw_on_ctlr_branch = tw_initconnect->fw_branch;
+			*fw_on_ctlr_build = tw_initconnect->fw_build;
+			*init_connect_result = tw_initconnect->result;
+		}
+		retval = 0;
+	}
+
+	tw_dev->posted_request_count--;
+	tw_dev->state[request_id] = TW_S_INITIAL;
+
+	return retval;
+} /* End twa_initconnection() */
+
+/* This function will initialize the fields of a device extension */
+static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
+{
+	int i, retval = 1;
+
+	/* Initialize command packet buffers */
+	if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");
+		goto out;
+	}
+
+	/* Initialize generic buffer */
+	if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");
+		goto out;
+	}
+
+	/* Allocate event info space */
+	tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_ATOMIC);
+	if (!tw_dev->event_queue[0]) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
+		goto out;
+	}
+
+	memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);
+
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+
+	tw_dev->pending_head = TW_Q_START;
+	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->free_head = TW_Q_START;
+	tw_dev->free_tail = TW_Q_START;
+	tw_dev->error_sequence_id = 1;
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+
+	init_MUTEX(&tw_dev->ioctl_sem);
+	init_waitqueue_head(&tw_dev->ioctl_wqueue);
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_initialize_device_extension() */
+
+/* This function is the interrupt service routine */
+static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	int request_id, error = 0;
+	u32 status_reg_value;
+	TW_Response_Queue response_que;
+	unsigned long flags = 0;
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
+	int handled = 0;
+
+	/* See if we are already running on another processor */
+	if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags))
+		return IRQ_NONE;
+
+	/* Get the per adapter lock */
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
+
+	/* See if the interrupt matches this instance */
+	if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) {
+
+		handled = 1;
+
+		/* Read the registers */
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+		/* Check if this is our interrupt, otherwise bail */
+		if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+			goto twa_interrupt_bail;
+
+		/* Check controller for errors */
+		if (twa_check_bits(status_reg_value)) {
+			if (twa_decode_bits(tw_dev, status_reg_value)) {
+				TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+				goto twa_interrupt_bail;
+			}
+		}
+
+		/* Handle host interrupt */
+		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
+			TW_CLEAR_HOST_INTERRUPT(tw_dev);
+
+		/* Handle attention interrupt */
+		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+			TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+			if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
+				twa_get_request_id(tw_dev, &request_id);
+
+				error = twa_aen_read_queue(tw_dev, request_id);
+				if (error) {
+					tw_dev->state[request_id] = TW_S_COMPLETED;
+					twa_free_request_id(tw_dev, request_id);
+					clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+				}
+			}
+		}
+
+		/* Handle command interrupt */
+		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+			TW_MASK_COMMAND_INTERRUPT(tw_dev);
+			/* Drain as many pending commands as we can */
+			while (tw_dev->pending_request_count > 0) {
+				request_id = tw_dev->pending_queue[tw_dev->pending_head];
+				if (tw_dev->state[request_id] != TW_S_PENDING) {
+					TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
+					TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+					goto twa_interrupt_bail;
+				}
+				if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
+					tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
+					tw_dev->pending_request_count--;
+				} else {
+					/* If we get here, we will continue re-posting on the next command interrupt */
+					break;
+				}
+			}
+		}
+
+		/* Handle response interrupt */
+		if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
+
+			/* Drain the response queue from the board */
+			while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+				/* Complete the response */
+				response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+				request_id = response_que.u.response_id;
+				full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+				error = 0;
+				command_packet = &full_command_packet->command.oldcommand;
+				/* Check for command packet errors */
+				if (full_command_packet->command.newcommand.status != 0) {
+					if (tw_dev->srb[request_id] != 0) {
+						error = twa_fill_sense(tw_dev, request_id, 1, 1);
+					} else {
+						/* Skip ioctl error prints */
+						if (request_id != tw_dev->chrdev_request_id) {
+							error = twa_fill_sense(tw_dev, request_id, 0, 1);
+						}
+					}
+				}
+
+				/* Check for correct state */
+				if (tw_dev->state[request_id] != TW_S_POSTED) {
+					if (tw_dev->srb[request_id] != 0) {
+						TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
+					        TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+						goto twa_interrupt_bail;
+					}
+				}
+
+				/* Check for internal command completion */
+				if (tw_dev->srb[request_id] == 0) {
+					if (request_id != tw_dev->chrdev_request_id) {
+						if (twa_aen_complete(tw_dev, request_id))
+							TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
+					} else {
+						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+						wake_up(&tw_dev->ioctl_wqueue);
+					}
+				} else {
+					twa_scsiop_execute_scsi_complete(tw_dev, request_id);
+					/* If no error command was a success */
+					if (error == 0) {
+						tw_dev->srb[request_id]->result = (DID_OK << 16);
+					}
+
+					/* If error, command failed */
+					if (error == 1) {
+						/* Ask for a host reset */
+						tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+					}
+
+					/* Now complete the io */
+					tw_dev->state[request_id] = TW_S_COMPLETED;
+					twa_free_request_id(tw_dev, request_id);
+					tw_dev->posted_request_count--;
+					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+					twa_unmap_scsi_data(tw_dev, request_id);
+				}
+
+				/* Check for valid status after each drain */
+				status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+				if (twa_check_bits(status_reg_value)) {
+					if (twa_decode_bits(tw_dev, status_reg_value)) {
+						TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+						goto twa_interrupt_bail;
+					}
+				}
+			}
+		}
+	}
+twa_interrupt_bail:
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+	clear_bit(TW_IN_INTR, &tw_dev->flags);
+	return IRQ_RETVAL(handled);
+} /* End twa_interrupt() */
+
+/* This function will load the request id and various sgls for ioctls */
+static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
+{
+	TW_Command *oldcommand;
+	TW_Command_Apache *newcommand;
+	TW_SG_Entry *sgl;
+
+	if (full_command_packet->command.newcommand.command.opcode == TW_OP_EXECUTE_SCSI) {
+		newcommand = &full_command_packet->command.newcommand;
+		newcommand->request_id = request_id;
+		newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
+		newcommand->sg_list[0].length = length;
+	} else {
+		oldcommand = &full_command_packet->command.oldcommand;
+		oldcommand->request_id = request_id;
+
+		if (oldcommand->byte0_offset.sgl_offset) {
+			/* Load the sg list */
+			sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->byte0_offset.sgl_offset);
+			sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
+			sgl->length = length;
+		}
+	}
+} /* End twa_load_sgl() */
+
+/* This function will perform a pci-dma mapping for a scatter gather list */
+static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	int use_sg;
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+	int retval = 0;
+
+	if (cmd->use_sg == 0)
+		goto out;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+
+	if (use_sg == 0) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
+		goto out;
+	}
+
+	cmd->SCp.phase = 2;
+	cmd->SCp.have_data_in = use_sg;
+	retval = use_sg;
+out:
+	return retval;
+} /* End twa_map_scsi_sg_data() */
+
+/* This function will perform a pci-dma map for a single buffer */
+static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	dma_addr_t mapping;
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+	int retval = 0;
+
+	if (cmd->request_bufflen == 0) {
+		retval = 0;
+		goto out;
+	}
+
+	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+
+	if (mapping == 0) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page");
+		goto out;
+	}
+
+	cmd->SCp.phase = 1;
+	cmd->SCp.have_data_in = mapping;
+	retval = mapping;
+out:
+	return retval;
+} /* End twa_map_scsi_single_data() */
+
+/* This function will poll for a response interrupt of a request */
+static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
+{
+	int retval = 1, found = 0, response_request_id;
+	TW_Response_Queue response_queue;
+	TW_Command_Full *full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+
+	if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) {
+		response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		response_request_id = (unsigned char)response_queue.u.response_id;
+		if (request_id != response_request_id) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response");
+			goto out;
+		}
+		if (full_command_packet->command.newcommand.command.opcode == TW_OP_EXECUTE_SCSI) {
+			if (full_command_packet->command.newcommand.status != 0) {
+				/* bad response */
+				twa_fill_sense(tw_dev, request_id, 0, 0);
+				goto out;
+			}
+			found = 1;
+		} else {
+			if (full_command_packet->command.oldcommand.status != 0) {
+				/* bad response */
+				twa_fill_sense(tw_dev, request_id, 0, 0);
+				goto out;
+			}
+			found = 1;
+		}
+	}
+
+	if (found)
+		retval = 0;
+out:
+	return retval;
+} /* End twa_poll_response() */
+
+/* This function will poll the status register for a flag */
+static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+	u32 status_reg_value;
+	unsigned long before;
+	int retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+	before = jiffies;
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	while ((status_reg_value & flag) != flag) {
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+		if (twa_check_bits(status_reg_value))
+			twa_decode_bits(tw_dev, status_reg_value);
+
+		if (time_after(jiffies, before + HZ * seconds))
+			goto out;
+
+		mdelay(5);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_poll_status() */
+
+/* This function will poll the status register for disappearance of a flag */
+static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+	u32 status_reg_value;
+	unsigned long before;
+	int retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+	before = jiffies;
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	while ((status_reg_value & flag) != 0) {
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+		if (twa_check_bits(status_reg_value))
+			twa_decode_bits(tw_dev, status_reg_value);
+
+		if (time_after(jiffies, before + HZ * seconds))
+			goto out;
+
+		mdelay(5);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_poll_status_gone() */
+
+/* This function will attempt to post a command packet to the board */
+static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
+{
+	u32 status_reg_value;
+	unsigned long command_que_value;
+	int retval = 1;
+
+	command_que_value = tw_dev->command_packet_phys[request_id];
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) {
+
+		/* Only pend internal driver commands */
+		if (!internal) {
+			retval = SCSI_MLQUEUE_HOST_BUSY;
+			goto out;
+		}
+
+		/* Couldn't post the command packet, so we do it later */
+		if (tw_dev->state[request_id] != TW_S_PENDING) {
+			tw_dev->state[request_id] = TW_S_PENDING;
+			tw_dev->pending_request_count++;
+			if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
+				tw_dev->max_pending_request_count = tw_dev->pending_request_count;
+			}
+			tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
+			tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH;
+		}
+		TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
+		goto out;
+	} else {
+		/* We successfully posted the command packet */
+#if BITS_PER_LONG > 32
+		writeq(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+#else
+		writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+#endif
+		tw_dev->state[request_id] = TW_S_POSTED;
+		tw_dev->posted_request_count++;
+		if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
+			tw_dev->max_posted_request_count = tw_dev->posted_request_count;
+		}
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_post_command_packet() */
+
+/* This function will reset a device extension */
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
+{
+	int i = 0;
+	int retval = 1;
+
+	/* Abort all requests that are in progress */
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		if ((tw_dev->state[i] != TW_S_FINISHED) &&
+		    (tw_dev->state[i] != TW_S_INITIAL) &&
+		    (tw_dev->state[i] != TW_S_COMPLETED)) {
+			if (tw_dev->srb[i]) {
+				tw_dev->srb[i]->result = (DID_RESET << 16);
+				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				twa_unmap_scsi_data(tw_dev, i);
+			}
+		}
+	}
+
+	/* Reset queues and counts */
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+	tw_dev->free_head = TW_Q_START;
+	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;
+	tw_dev->flags = 0;
+
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	if (twa_reset_sequence(tw_dev, 1))
+		goto out;
+
+        TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_reset_device_extension() */
+
+/* This function will reset a controller */
+static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
+{
+	int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
+
+	while (tries < TW_MAX_RESET_TRIES) {
+		if (do_soft_reset)
+			TW_SOFT_RESET(tw_dev);
+
+		/* Make sure controller is in a good state */
+		if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 30)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		/* Empty response queue */
+		if (twa_empty_response_queue(tw_dev)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		flashed = 0;
+
+		/* Check for compatibility/flash */
+		if (twa_check_srl(tw_dev, &flashed)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		} else {
+			if (flashed) {
+				tries++;
+				continue;
+			}
+		}
+
+		/* Drain the AEN queue */
+		if (twa_aen_drain_queue(tw_dev, soft_reset)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		/* If we got here, controller is in a good state */
+		retval = 0;
+		goto out;
+	}
+out:
+	return retval;
+} /* End twa_reset_sequence() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
+{
+	int heads, sectors, cylinders;
+	TW_Device_Extension *tw_dev;
+
+	tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
+
+	if (capacity >= 0x200000) {
+		heads = 255;
+		sectors = 63;
+		cylinders = sector_div(capacity, heads * sectors);
+	} else {
+		heads = 64;
+		sectors = 32;
+		cylinders = sector_div(capacity, heads * sectors);
+	}
+
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return 0;
+} /* End twa_scsi_biosparam() */
+
+/* This is the new scsi eh abort function */
+static int twa_scsi_eh_abort(struct scsi_cmnd *SCpnt)
+{
+	int i;
+	TW_Device_Extension *tw_dev = NULL;
+	int retval = FAILED;
+
+	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	tw_dev->num_aborts++;
+
+	/* If we find any IO's in process, we have to reset the card */
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL)) {
+			printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0x2c, SCpnt->device->id, SCpnt->cmnd[0]);
+			if (twa_reset_device_extension(tw_dev)) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2a, "Controller reset failed during scsi abort");
+				goto out;
+			}
+			break;
+		}
+	}
+	retval = SUCCESS;
+out:
+	return retval;
+} /* End twa_scsi_eh_abort() */
+
+/* This is the new scsi eh reset function */
+static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
+{
+	TW_Device_Extension *tw_dev = NULL;
+	int retval = FAILED;
+
+	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	tw_dev->num_resets++;
+
+	printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset started.\n", tw_dev->host->host_no);
+
+	/* Now reset the card and some of the device extension data */
+	if (twa_reset_device_extension(tw_dev)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
+		goto out;
+	}
+	printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset succeeded.\n", tw_dev->host->host_no);
+	retval = SUCCESS;
+out:
+	return retval;
+} /* End twa_scsi_eh_reset() */
+
+/* This is the main scsi queue function to handle scsi opcodes */
+static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	int request_id, retval;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	/* Save done function into scsi_cmnd struct */
+	SCpnt->scsi_done = done;
+
+	/* Get a free request id */
+	twa_get_request_id(tw_dev, &request_id);
+
+	/* Save the scsi command for use by the ISR */
+	tw_dev->srb[request_id] = SCpnt;
+
+	/* Initialize phase to zero */
+	SCpnt->SCp.phase = 0;
+
+	retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
+	switch (retval) {
+	case SCSI_MLQUEUE_HOST_BUSY:
+		twa_free_request_id(tw_dev, request_id);
+		break;
+	case 1:
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		twa_free_request_id(tw_dev, request_id);
+		SCpnt->result = (DID_ERROR << 16);
+		done(SCpnt);
+	}
+
+	return retval;
+} /* End twa_scsi_queue() */
+
+/* This function hands scsi cdb's to the firmware */
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command_Apache *command_packet;
+	u32 num_sectors = 0x0;
+	int i, sg_count;
+	struct scsi_cmnd *srb = NULL;
+	struct scatterlist *sglist = NULL;
+	u32 buffaddr = 0x0;
+	int retval = 1;
+
+	if (tw_dev->srb[request_id]) {
+		if (tw_dev->srb[request_id]->request_buffer) {
+			sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+		}
+		srb = tw_dev->srb[request_id];
+	}
+
+	/* Initialize command packet */
+	full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id];
+	full_command_packet->header.header_desc.size_header = 128;
+	full_command_packet->header.status_block.error = 0;
+	full_command_packet->header.status_block.substatus_block.severity = 0;
+
+	command_packet = &full_command_packet->command.newcommand;
+	command_packet->status = 0;
+	command_packet->command.opcode = TW_OP_EXECUTE_SCSI;
+
+	/* We forced 16 byte cdb use earlier */
+	if (!cdb)
+		memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
+	else
+		memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
+
+	if (srb)
+		command_packet->unit = srb->device->id;
+	else
+		command_packet->unit = 0;
+
+	command_packet->request_id = request_id;
+	command_packet->sgl_offset = 16;
+
+	if (!sglistarg) {
+		/* Map sglist from scsi layer to cmd packet */
+		if (tw_dev->srb[request_id]->use_sg == 0) {
+			if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) {
+				command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
+				command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+			} else {
+				buffaddr = twa_map_scsi_single_data(tw_dev, request_id);
+				if (buffaddr == 0)
+					goto out;
+
+				command_packet->sg_list[0].address = buffaddr;
+				command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen;
+			}
+			command_packet->sgl_entries = 1;
+
+			if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi");
+				goto out;
+			}
+		}
+
+		if (tw_dev->srb[request_id]->use_sg > 0) {
+			sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
+			if (sg_count == 0)
+				goto out;
+
+			for (i = 0; i < sg_count; i++) {
+				command_packet->sg_list[i].address = sg_dma_address(&sglist[i]);
+				command_packet->sg_list[i].length = sg_dma_len(&sglist[i]);
+				if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+					TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
+					goto out;
+				}
+			}
+			command_packet->sgl_entries = tw_dev->srb[request_id]->use_sg;
+		}
+	} else {
+		/* Internal cdb post */
+		for (i = 0; i < use_sg; i++) {
+			command_packet->sg_list[i].address = sglistarg[i].address;
+			command_packet->sg_list[i].length = sglistarg[i].length;
+			if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
+				goto out;
+			}
+		}
+		command_packet->sgl_entries = use_sg;
+	}
+
+	if (srb) {
+		if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6)
+			num_sectors = (u32)srb->cmnd[4];
+
+		if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10)
+			num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
+	}
+
+	/* Update sector statistic */
+	tw_dev->sector_count = num_sectors;
+	if (tw_dev->sector_count > tw_dev->max_sector_count)
+		tw_dev->max_sector_count = tw_dev->sector_count;
+
+	/* Update SG statistics */
+	if (srb) {
+		tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+		if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+			tw_dev->max_sgl_entries = tw_dev->sgl_entries;
+	}
+
+	/* Now post the command to the board */
+	if (srb) {
+		retval = twa_post_command_packet(tw_dev, request_id, 0);
+	} else {
+		twa_post_command_packet(tw_dev, request_id, 1);
+		retval = 0;
+	}
+out:
+	return retval;
+} /* End twa_scsiop_execute_scsi() */
+
+/* This function completes an execute scsi operation */
+static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	/* Copy the response if too small */
+	if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+		memcpy(tw_dev->srb[request_id]->request_buffer, tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_bufflen);
+	}
+} /* End twa_scsiop_execute_scsi_complete() */
+
+/* This function will setup the interrupt handler */
+static int twa_setup_irq(TW_Device_Extension *tw_dev)
+{
+	char *device = TW_DEVICE_NAME;
+	int retval = 1;
+
+	if (request_irq(tw_dev->tw_pci_dev->irq, twa_interrupt, SA_SHIRQ, device, tw_dev) < 0) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_setup_irq() */
+
+/* This function tells the controller to shut down */
+static void __twa_shutdown(TW_Device_Extension *tw_dev)
+{
+	/* Disable interrupts */
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
+
+	/* Tell the card we are shutting down */
+	if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed");
+	} else {
+		printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n");
+	}
+
+	/* Clear all interrupts just before exit */
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+} /* End __twa_shutdown() */
+
+/* Wrapper for __twa_shutdown */
+static void twa_shutdown(struct device *dev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	__twa_shutdown(tw_dev);
+} /* End twa_shutdown() */
+
+/* This function will configure individual target parameters */
+static int twa_slave_configure(struct scsi_device *SDptr)
+{
+	int max_cmds;
+
+	if (cmds_per_lun) {
+		max_cmds = cmds_per_lun;
+		if (max_cmds > TW_MAX_CMDS_PER_LUN)
+			max_cmds = TW_MAX_CMDS_PER_LUN;
+	} else {
+		max_cmds = TW_MAX_CMDS_PER_LUN;
+	}
+	scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, max_cmds);
+
+	return 0;
+} /* End twa_slave_configure */
+
+/* This function will look up a string */
+static char *twa_string_lookup(twa_message_type *table, unsigned int code)
+{
+	int index;
+
+	for (index = 0; ((code != table[index].code) &&
+		      (table[index].text != (char *)0)); index++);
+	return(table[index].text);
+} /* End twa_string_lookup() */
+
+/* This function will perform a pci-dma unmap */
+static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+
+	switch(cmd->SCp.phase) {
+	case 1:
+		pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+		break;
+	case 2:
+		pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+		break;
+	}
+} /* End twa_unmap_scsi_data() */
+
+/* Get informationa bout the card/driver */
+static const char *twa_info(struct Scsi_Host *host)
+{
+	static char buffer[512];
+
+	sprintf(buffer, "3ware 9000 Storage Controller");
+
+	return buffer;
+} /* End twa_info() */
+
+/* scsi_host_template initializer */
+static struct scsi_host_template driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "3ware 9000 Storage Controller",
+	.info			= twa_info,
+	.queuecommand		= twa_scsi_queue,
+	.eh_abort_handler	= twa_scsi_eh_abort,
+	.eh_host_reset_handler	= twa_scsi_eh_reset,
+	.bios_param		= twa_scsi_biosparam,
+	.slave_configure	= twa_slave_configure,
+	.can_queue		= TW_Q_LENGTH-2,
+	.this_id		= -1,
+	.sg_tablesize		= TW_APACHE_MAX_SGL_LENGTH,
+	.max_sectors		= TW_MAX_SECTORS,
+	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= twa_host_attrs,
+	.emulated		= 1
+};
+
+/* This function will probe and initialize a card */
+static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+{
+	struct Scsi_Host *host = NULL;
+	TW_Device_Extension *tw_dev;
+	u32 mem_addr, mem_len;
+	int retval = -ENODEV;
+
+	if (pci_enable_device(pdev)) {
+		TW_PRINTK(host, TW_DRIVER, 0x32, "Failed to enable pci device");
+		goto out;
+	}
+
+	pci_set_master(pdev);
+
+	if (pci_set_dma_mask(pdev, TW_DMA_MASK)) {
+		TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
+		goto out;
+	}
+
+	host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
+	if (!host) {
+		TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension");
+		retval = -ENOMEM;
+		goto out;
+	}
+	tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	memset(tw_dev, 0, sizeof(TW_Device_Extension));
+
+	/* Save values to device extension */
+	tw_dev->host = host;
+	tw_dev->tw_pci_dev = pdev;
+
+	if (twa_initialize_device_extension(tw_dev)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
+		goto out_free_device_extension;
+	}
+
+	mem_addr = pci_resource_start(pdev, 1);
+	mem_len = pci_resource_len(pdev, 1);
+
+	/* Make sure that mem region isn't already taken */
+	if (check_mem_region(mem_addr, mem_len)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region");
+		goto out_free_device_extension;
+	}
+
+	/* Reserve the mem address space */
+	request_mem_region(mem_addr, mem_len, TW_DEVICE_NAME);
+
+	/* Save base address */
+	tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
+
+	/* Disable interrupts on the card */
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	/* Initialize the card */
+	if (twa_reset_sequence(tw_dev, 0))
+		goto out_release_mem_region;
+
+	/* Set host specific parameters */
+	host->max_id = TW_MAX_UNITS;
+	host->max_cmd_len = TW_MAX_CDB_LEN;
+	host->max_lun = 0;
+	host->max_channel = 0;
+
+	/* Register the card with the kernel SCSI layer */
+	retval = scsi_add_host(host, &pdev->dev);
+	if (retval) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
+		goto out_release_mem_region;
+	}
+
+	pci_set_drvdata(pdev, host);
+
+	printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n", host->host_no, mem_addr, pdev->irq);
+	printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n", host->host_no, (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE, TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE, TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), *(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH));
+
+	/* Now setup the interrupt handler */
+	if (twa_setup_irq(tw_dev))
+		goto out_remove_host;
+
+	twa_device_extension_list[twa_device_extension_count] = tw_dev;
+	twa_device_extension_count++;
+
+	/* Re-enable interrupts on the card */
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+	/* Finally, scan the host */
+	scsi_scan_host(host);
+
+	if (twa_major == -1) {
+		if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0)
+			TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device");
+	}
+	return 0;
+
+out_remove_host:
+	scsi_remove_host(host);
+out_release_mem_region:
+	release_mem_region(mem_addr, mem_len);
+out_free_device_extension:
+	twa_free_device_extension(tw_dev);
+	scsi_host_put(host);
+out:
+	return retval;
+} /* End twa_probe() */
+
+/* This function is called to remove a device */
+static void twa_remove(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	scsi_remove_host(tw_dev->host);
+
+	__twa_shutdown(tw_dev);
+
+	/* Free up the IRQ */
+	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
+	/* Free up the mem region */
+	release_mem_region(pci_resource_start(tw_dev->tw_pci_dev, 1), pci_resource_len(tw_dev->tw_pci_dev, 1));
+
+	/* Free up device extension resources */
+	twa_free_device_extension(tw_dev);
+
+	scsi_host_put(tw_dev->host);
+	pci_disable_device(pdev);
+	twa_device_extension_count--;
+} /* End twa_remove() */
+
+/* PCI Devices supported by this driver */
+static struct pci_device_id twa_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
+
+/* pci_driver initializer */
+static struct pci_driver twa_driver = {
+	.name		= "3w-9xxx",
+	.id_table	= twa_pci_tbl,
+	.probe		= twa_probe,
+	.remove		= twa_remove,
+	.driver		= {
+		.shutdown = twa_shutdown
+	}
+};
+
+/* This function is called on driver initialization */
+static int __init twa_init(void)
+{
+	printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", twa_driver_version);
+
+	pci_register_driver(&twa_driver);
+
+	return 0;
+} /* End twa_init() */
+
+/* This function is called on driver exit */
+static void __exit twa_exit(void)
+{
+	/* Unregister character device */
+	if (twa_major >= 0) {
+		unregister_chrdev(twa_major, "twa");
+		twa_major = -1;
+	}
+
+	pci_unregister_driver(&twa_driver);
+} /* End twa_exit() */
+
+module_init(twa_init);
+module_exit(twa_exit);
+
--- diff/drivers/scsi/3w-9xxx.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/scsi/3w-9xxx.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,726 @@
+/*
+   3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linuxraid@amcc.com>
+
+   Copyright (C) 2004 Applied Micro Circuits Corporation.
+
+   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; version 2 of the License.
+
+   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.
+
+   NO WARRANTY
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+   solely responsible for determining the appropriateness of using and
+   distributing the Program and assumes all risks associated with its
+   exercise of rights under this Agreement, including but not limited to
+   the risks and costs of program errors, damage to or loss of data,
+   programs or equipment, and unavailability or interruption of operations.
+
+   DISCLAIMER OF LIABILITY
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+   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
+
+   Bugs/Comments/Suggestions should be mailed to:
+   linuxraid@amcc.com
+
+   For more information, goto:
+   http://www.amcc.com
+*/
+
+#ifndef _3W_9XXX_H
+#define _3W_9XXX_H
+
+/* AEN string type */
+typedef struct TAG_twa_message_type {
+  unsigned int   code;
+  char*          text;
+} twa_message_type;
+
+/* AEN strings */
+static twa_message_type twa_aen_table[] = {
+	{0x0000, "AEN queue empty"},
+	{0x0001, "Controller reset occurred"},
+	{0x0002, "Degraded unit detected"},
+	{0x0003, "Controller error occured"},
+	{0x0004, "Background rebuild failed"},
+	{0x0005, "Background rebuild done"},
+	{0x0006, "Incomplete unit detected"},
+	{0x0007, "Background initialize done"},
+	{0x0008, "Unclean shutdown detected"},
+	{0x0009, "Drive timeout detected"},
+	{0x000A, "Drive error detected"},
+	{0x000B, "Rebuild started"},
+	{0x000C, "Background initialize started"},
+	{0x000D, "Entire logical unit was deleted"},
+	{0x000E, "Background initialize failed"},
+	{0x000F, "SMART attribute exceeded threshold"},
+	{0x0010, "Power supply reported AC under range"},
+	{0x0011, "Power supply reported DC out of range"},
+	{0x0012, "Power supply reported a malfunction"},
+	{0x0013, "Power supply predicted malfunction"},
+	{0x0014, "Battery charge is below threshold"},
+	{0x0015, "Fan speed is below threshold"},
+	{0x0016, "Temperature sensor is above threshold"},
+	{0x0017, "Power supply was removed"},
+	{0x0018, "Power supply was inserted"},
+	{0x0019, "Drive was removed from a bay"},
+	{0x001A, "Drive was inserted into a bay"},
+	{0x001B, "Drive bay cover door was opened"},
+	{0x001C, "Drive bay cover door was closed"},
+	{0x001D, "Product case was opened"},
+	{0x0020, "Prepare for shutdown (power-off)"},
+	{0x0021, "Downgrade UDMA mode to lower speed"},
+	{0x0022, "Upgrade UDMA mode to higher speed"},
+	{0x0023, "Sector repair completed"},
+	{0x0024, "Sbuf memory test failed"},
+	{0x0025, "Error flushing cached write data to array"},
+	{0x0026, "Drive reported data ECC error"},
+	{0x0027, "DCB has checksum error"},
+	{0x0028, "DCB version is unsupported"},
+	{0x0029, "Background verify started"},
+	{0x002A, "Background verify failed"},
+	{0x002B, "Background verify done"},
+	{0x002C, "Bad sector overwritten during rebuild"},
+	{0x002D, "Background rebuild error on source drive"},
+	{0x002E, "Replace failed because replacement drive too small"},
+	{0x002F, "Verify failed because array was never initialized"},
+	{0x0030, "Unsupported ATA drive"},
+	{0x0031, "Synchronize host/controller time"},
+	{0x0032, "Spare capacity is inadequate for some units"},
+	{0x0033, "Background migration started"},
+	{0x0034, "Background migration failed"},
+	{0x0035, "Background migration done"},
+	{0x0036, "Verify detected and fixed data/parity mismatch"},
+	{0x0037, "SO-DIMM incompatible"},
+	{0x0038, "SO-DIMM not detected"},
+	{0x0039, "Corrected Sbuf ECC error"},
+	{0x003A, "Drive power on reset detected"},
+	{0x003B, "Background rebuild paused"},
+	{0x003C, "Background initialize paused"},
+	{0x003D, "Background verify paused"},
+	{0x003E, "Background migration paused"},
+	{0x003F, "Corrupt flash file system detected"},
+	{0x0040, "Flash file system repaired"},
+	{0x0041, "Unit number assignments were lost"},
+	{0x0042, "Error during read of primary DCB"},
+	{0x0043, "Latent error found in backup DCB"},
+	{0x00FC, "Recovered/finished array membership update"},
+	{0x00FD, "Handler lockup"},
+	{0x00FE, "Retrying PCI transfer"},
+	{0x00FF, "AEN queue is full"},
+	{0xFFFFFFFF, (char*) 0}
+};
+
+/* AEN severity table */
+static char *twa_aen_severity_table[] =
+{
+	"None", "ERROR", "WARNING", "INFO", "DEBUG", (char*) 0
+};
+
+/* Error strings */
+static twa_message_type twa_error_table[] = {
+	{0x0100, "SGL entry contains zero data"},
+	{0x0101, "Invalid command opcode"},
+	{0x0102, "SGL entry has unaligned address"},
+	{0x0103, "SGL size does not match command"},
+	{0x0104, "SGL entry has illegal length"},
+	{0x0105, "Command packet is not aligned"},
+	{0x0106, "Invalid request ID"},
+	{0x0107, "Duplicate request ID"},
+	{0x0108, "ID not locked"},
+	{0x0109, "LBA out of range"},
+	{0x010A, "Logical unit not supported"},
+	{0x010B, "Parameter table does not exist"},
+	{0x010C, "Parameter index does not exist"},
+	{0x010D, "Invalid field in CDB"},
+	{0x010E, "Specified port has invalid drive"},
+	{0x010F, "Parameter item size mismatch"},
+	{0x0110, "Failed memory allocation"},
+	{0x0111, "Memory request too large"},
+	{0x0112, "Out of memory segments"},
+	{0x0113, "Invalid address to deallocate"},
+	{0x0114, "Out of memory"},
+	{0x0115, "Out of heap"},
+	{0x0120, "Double degrade"},
+	{0x0121, "Drive not degraded"},
+	{0x0122, "Reconstruct error"},
+	{0x0123, "Replace not accepted"},
+	{0x0124, "Replace drive capacity too small"},
+	{0x0125, "Sector count not allowed"},
+	{0x0126, "No spares left"},
+	{0x0127, "Reconstruct error"},
+	{0x0128, "Unit is offline"},
+	{0x0129, "Cannot update status to DCB"},
+	{0x0130, "Invalid stripe handle"},
+	{0x0131, "Handle that was not locked"},
+	{0x0132, "Handle that was not empty"},
+	{0x0133, "Handle has different owner"},
+	{0x0140, "IPR has parent"},
+	{0x0150, "Illegal Pbuf address alignment"},
+	{0x0151, "Illegal Pbuf transfer length"},
+	{0x0152, "Illegal Sbuf address alignment"},
+	{0x0153, "Illegal Sbuf transfer length"},
+	{0x0160, "Command packet too large"},
+	{0x0161, "SGL exceeds maximum length"},
+	{0x0162, "SGL has too many entries"},
+	{0x0170, "Insufficient resources for rebuilder"},
+	{0x0171, "Verify error (data != parity)"},
+	{0x0180, "Requested segment not in directory of this DCB"},
+	{0x0181, "DCB segment has unsupported version"},
+	{0x0182, "DCB segment has checksum error"},
+	{0x0183, "DCB support (settings) segment invalid"},
+	{0x0184, "DCB UDB (unit descriptor block) segment invalid"},
+	{0x0185, "DCB GUID (globally unique identifier) segment invalid"},
+	{0x01A0, "Could not clear Sbuf"},
+	{0x01C0, "Flash identify failed"},
+	{0x01C1, "Flash out of bounds"},
+	{0x01C2, "Flash verify error"},
+	{0x01C3, "Flash file object not found"},
+	{0x01C4, "Flash file already present"},
+	{0x01C5, "Flash file system full"},
+	{0x01C6, "Flash file not present"},
+	{0x01C7, "Flash file size error"},
+	{0x01C8, "Bad flash file checksum"},
+	{0x01CA, "Corrupt flash file system detected"},
+	{0x01D0, "Invalid field in parameter list"},
+	{0x01D1, "Parameter list length error"},
+	{0x01D2, "Parameter item is not changeable"},
+	{0x01D3, "Parameter item is not saveable"},
+	{0x0200, "UDMA CRC error"},
+	{0x0201, "Internal CRC error"},
+	{0x0202, "Data ECC error"},
+	{0x0203, "ADP level 1 error"},
+	{0x0204, "Port timeout"},
+	{0x0205, "Drive power on reset"},
+	{0x0206, "ADP level 2 error"},
+	{0x0207, "Soft reset failed"},
+	{0x0208, "Drive not ready"},
+	{0x0209, "Unclassified port error"},
+	{0x020A, "Drive aborted command"},
+	{0x0210, "Internal CRC error"},
+	{0x0211, "PCI abort error"},
+	{0x0212, "PCI parity error"},
+	{0x0213, "Port handler error"},
+	{0x0214, "Token interrupt count error"},
+	{0x0215, "Timeout waiting for PCI transfer"},
+	{0x0216, "Corrected buffer ECC"},
+	{0x0217, "Uncorrected buffer ECC"},
+	{0x0230, "Unsupported command during flash recovery"},
+	{0x0231, "Next image buffer expected"},
+	{0x0232, "Binary image architecture incompatible"},
+	{0x0233, "Binary image has no signature"},
+	{0x0234, "Binary image has bad checksum"},
+	{0x0235, "Image downloaded overflowed buffer"},
+	{0x0240, "I2C device not found"},
+	{0x0241, "I2C transaction aborted"},
+	{0x0242, "SO-DIMM parameter(s) incompatible using defaults"},
+	{0x0243, "SO-DIMM unsupported"},
+	{0x0248, "SPI transfer status error"},
+	{0x0249, "SPI transfer timeout error"},
+	{0x0250, "Invalid unit descriptor size in CreateUnit"},
+	{0x0251, "Unit descriptor size exceeds data buffer in CreateUnit"},
+	{0x0252, "Invalid value in CreateUnit descriptor"},
+	{0x0253, "Inadequate disk space to support descriptor in CreateUnit"},
+	{0x0254, "Unable to create data channel for this unit descriptor"},
+	{0x0255, "CreateUnit descriptor specifies a drive already in use"},
+	{0x0256, "Unable to write configuration to all disks during CreateUnit"},
+	{0x0257, "CreateUnit does not support this descriptor version"},
+	{0x0258, "Invalid subunit for RAID 0 or 5 in CreateUnit"},
+	{0x0259, "Too many descriptors in CreateUnit"},
+	{0x025A, "Invalid configuration specified in CreateUnit descriptor"},
+	{0x025B, "Invalid LBA offset specified in CreateUnit descriptor"},
+	{0x025C, "Invalid stripelet size specified in CreateUnit descriptor"},
+	{0x0260, "SMART attribute exceeded threshold"},
+	{0xFFFFFFFF, (char*) 0}
+};
+
+/* Control register bit definitions */
+#define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
+#define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT   0x00040000
+#define TW_CONTROL_MASK_COMMAND_INTERRUPT      0x00020000
+#define TW_CONTROL_MASK_RESPONSE_INTERRUPT     0x00010000
+#define TW_CONTROL_UNMASK_COMMAND_INTERRUPT    0x00008000
+#define TW_CONTROL_UNMASK_RESPONSE_INTERRUPT   0x00004000
+#define TW_CONTROL_CLEAR_ERROR_STATUS	       0x00000200
+#define TW_CONTROL_ISSUE_SOFT_RESET	       0x00000100
+#define TW_CONTROL_ENABLE_INTERRUPTS	       0x00000080
+#define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
+#define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
+#define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
+#define TW_CONTROL_CLEAR_QUEUE_ERROR           0x00400000
+#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
+#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR      0x00000008
+
+/* Status register bit definitions */
+#define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
+#define TW_STATUS_MINOR_VERSION_MASK	       0x0F000000
+#define TW_STATUS_PCI_PARITY_ERROR	       0x00800000
+#define TW_STATUS_QUEUE_ERROR		       0x00400000
+#define TW_STATUS_MICROCONTROLLER_ERROR	       0x00200000
+#define TW_STATUS_PCI_ABORT		       0x00100000
+#define TW_STATUS_HOST_INTERRUPT	       0x00080000
+#define TW_STATUS_ATTENTION_INTERRUPT	       0x00040000
+#define TW_STATUS_COMMAND_INTERRUPT	       0x00020000
+#define TW_STATUS_RESPONSE_INTERRUPT	       0x00010000
+#define TW_STATUS_COMMAND_QUEUE_FULL	       0x00008000
+#define TW_STATUS_RESPONSE_QUEUE_EMPTY	       0x00004000
+#define TW_STATUS_MICROCONTROLLER_READY	       0x00002000
+#define TW_STATUS_COMMAND_QUEUE_EMPTY	       0x00001000
+#define TW_STATUS_EXPECTED_BITS		       0x00002000
+#define TW_STATUS_UNEXPECTED_BITS	       0x00F00008
+#define TW_STATUS_SBUF_WRITE_ERROR             0x00000008
+#define TW_STATUS_VALID_INTERRUPT              0x00DF0008
+
+/* RESPONSE QUEUE BIT DEFINITIONS */
+#define TW_RESPONSE_ID_MASK		       0x00000FF0
+
+/* PCI related defines */
+#define TW_DEVICE_NAME			       "3w-9xxx"
+#define TW_NUMDEVICES 1
+#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
+#define TW_PCI_CLEAR_PCI_ABORT     0x2000
+
+/* Command packet opcodes used by the driver */
+#define TW_OP_INIT_CONNECTION 0x1
+#define TW_OP_GET_PARAM	      0x12
+#define TW_OP_SET_PARAM	      0x13
+#define TW_OP_EXECUTE_SCSI    0x10
+#define TW_OP_DOWNLOAD_FIRMWARE 0x16
+#define TW_OP_RESET             0x1C
+
+/* Asynchronous Event Notification (AEN) codes used by the driver */
+#define TW_AEN_QUEUE_EMPTY       0x0000
+#define TW_AEN_SOFT_RESET        0x0001
+#define TW_AEN_SYNC_TIME_WITH_HOST 0x031
+#define TW_AEN_SEVERITY_ERROR    0x1
+#define TW_AEN_SEVERITY_DEBUG    0x4
+#define TW_AEN_NOT_RETRIEVED 0x1
+#define TW_AEN_RETRIEVED 0x2
+
+/* Command state defines */
+#define TW_S_INITIAL   0x1  /* Initial state */
+#define TW_S_STARTED   0x2  /* Id in use */
+#define TW_S_POSTED    0x4  /* Posted to the controller */
+#define TW_S_PENDING   0x8  /* Waiting to be posted in isr */
+#define TW_S_COMPLETED 0x10 /* Completed by isr */
+#define TW_S_FINISHED  0x20 /* I/O completely done */
+
+/* Compatibility defines */
+#define TW_9000_ARCH_ID 0x5
+#define TW_CURRENT_FW_SRL 24
+#define TW_CURRENT_FW_BUILD 5
+#define TW_CURRENT_FW_BRANCH 1
+
+/* Misc defines */
+#define TW_SECTOR_SIZE                        512
+#define TW_ALIGNMENT_9000                     4  /* 4 bytes */
+#define TW_ALIGNMENT_9000_SGL                 0x3
+#define TW_MAX_UNITS			      16
+#define TW_INIT_MESSAGE_CREDITS		      0x100
+#define TW_INIT_COMMAND_PACKET_SIZE	      0x3
+#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED  0x6
+#define TW_EXTENDED_INIT_CONNECT	      0x2
+#define TW_BUNDLED_FW_SAFE_TO_FLASH	      0x4
+#define TW_CTLR_FW_RECOMMENDS_FLASH	      0x8
+#define TW_CTLR_FW_COMPATIBLE		      0x2
+#define TW_BASE_FW_SRL			      0x17
+#define TW_BASE_FW_BRANCH		      0
+#define TW_BASE_FW_BUILD		      1
+#if BITS_PER_LONG > 32
+#define TW_APACHE_MAX_SGL_LENGTH 72
+#define TW_ESCALADE_MAX_SGL_LENGTH 41
+#define TW_APACHE_CMD_PKT_SIZE 5
+#else
+#define TW_APACHE_MAX_SGL_LENGTH 109
+#define TW_ESCALADE_MAX_SGL_LENGTH 62
+#define TW_APACHE_CMD_PKT_SIZE 4
+#endif
+#define TW_ATA_PASS_SGL_MAX                   60
+#define TW_Q_LENGTH			      256
+#define TW_Q_START			      0
+#define TW_MAX_SLOT			      32
+#define TW_MAX_RESET_TRIES		      2
+#define TW_MAX_CMDS_PER_LUN		      254
+#define TW_MAX_RESPONSE_DRAIN		      256
+#define TW_MAX_AEN_DRAIN		      40
+#define TW_IN_INTR                            1
+#define TW_IN_IOCTL                           2
+#define TW_IN_CHRDEV_IOCTL                    3
+#define TW_IN_ATTENTION_LOOP		      4
+#define TW_MAX_SECTORS                        256
+#define TW_AEN_WAIT_TIME                      1000
+#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
+#define TW_MAX_CDB_LEN                        16
+#define TW_ISR_DONT_COMPLETE                  2
+#define TW_ISR_DONT_RESULT                    3
+#define TW_IOCTL_CHRDEV_TIMEOUT               60 /* 60 seconds */
+#define TW_IOCTL_CHRDEV_FREE                  -1
+#define TW_COMMAND_OFFSET                     128 /* 128 bytes */
+#define TW_VERSION_TABLE                      0x0402
+#define TW_TIMEKEEP_TABLE		      0x040A
+#define TW_INFORMATION_TABLE		      0x0403
+#define TW_PARAM_FWVER			      3
+#define TW_PARAM_FWVER_LENGTH		      16
+#define TW_PARAM_BIOSVER		      4
+#define TW_PARAM_BIOSVER_LENGTH		      16
+#define TW_PARAM_PORTCOUNT		      3
+#define TW_PARAM_PORTCOUNT_LENGTH	      1
+#define TW_MIN_SGL_LENGTH                     0x200 /* 512 bytes */
+#define TW_MAX_SENSE_LENGTH                   256
+#define TW_EVENT_SOURCE_AEN                   0x1000
+#define TW_EVENT_SOURCE_COMMAND               0x1001
+#define TW_EVENT_SOURCE_PCHIP                 0x1002
+#define TW_EVENT_SOURCE_DRIVER                0x1003
+#define TW_IOCTL_GET_COMPATIBILITY_INFO	      0x101
+#define TW_IOCTL_GET_LAST_EVENT               0x102
+#define TW_IOCTL_GET_FIRST_EVENT              0x103
+#define TW_IOCTL_GET_NEXT_EVENT               0x104
+#define TW_IOCTL_GET_PREVIOUS_EVENT           0x105
+#define TW_IOCTL_GET_LOCK                     0x106
+#define TW_IOCTL_RELEASE_LOCK                 0x107
+#define TW_IOCTL_FIRMWARE_PASS_THROUGH        0x108
+#define TW_IOCTL_ERROR_STATUS_NOT_LOCKED      0x1001 // Not locked
+#define TW_IOCTL_ERROR_STATUS_LOCKED          0x1002 // Already locked
+#define TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS  0x1003 // No more events
+#define TW_IOCTL_ERROR_STATUS_AEN_CLOBBER     0x1004 // AEN clobber occurred
+#define TW_IOCTL_ERROR_OS_EFAULT	      -EFAULT // Bad address
+#define TW_IOCTL_ERROR_OS_EINTR		      -EINTR  // Interrupted system call
+#define TW_IOCTL_ERROR_OS_EINVAL	      -EINVAL // Invalid argument
+#define TW_IOCTL_ERROR_OS_ENOMEM	      -ENOMEM // Out of memory
+#define TW_IOCTL_ERROR_OS_ERESTARTSYS	      -ERESTARTSYS // Restart system call
+#define TW_IOCTL_ERROR_OS_EIO		      -EIO // I/O error
+#define TW_IOCTL_ERROR_OS_ENOTTY	      -ENOTTY // Not a typewriter
+#define TW_IOCTL_ERROR_OS_ENODEV	      -ENODEV // No such device
+#define TW_ALLOCATION_LENGTH		      128
+#define TW_SENSE_DATA_LENGTH		      18
+#define TW_STATUS_CHECK_CONDITION	      2
+#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED   0x10a
+#define TW_ERROR_UNIT_OFFLINE                 0x128
+#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR    3
+#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT    4
+#define TW_MESSAGE_SOURCE_LINUX_DRIVER        6
+#define TW_DRIVER TW_MESSAGE_SOURCE_LINUX_DRIVER
+#define TW_MESSAGE_SOURCE_LINUX_OS            9
+#define TW_OS TW_MESSAGE_SOURCE_LINUX_OS
+#if BITS_PER_LONG > 32
+#define TW_COMMAND_SIZE			      5
+#define TW_DMA_MASK			      DMA_64BIT_MASK
+#else
+#define TW_COMMAND_SIZE			      4
+#define TW_DMA_MASK			      DMA_32BIT_MASK
+#endif
+
+/* Macros */
+#define TW_CONTROL_REG_ADDR(x) (x->base_addr)
+#define TW_STATUS_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x4)
+#if BITS_PER_LONG > 32
+#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x20)
+#else
+#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x8)
+#endif
+#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0xC)
+#define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_CLEAR_HOST_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_DISABLE_INTERRUPTS(x) (writel(TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_ENABLE_AND_CLEAR_INTERRUPTS(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_MASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_MASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_UNMASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_UNMASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_SOFT_RESET(x) (writel(TW_CONTROL_ISSUE_SOFT_RESET | \
+			TW_CONTROL_CLEAR_HOST_INTERRUPT | \
+			TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | \
+			TW_CONTROL_MASK_COMMAND_INTERRUPT | \
+			TW_CONTROL_MASK_RESPONSE_INTERRUPT | \
+			TW_CONTROL_CLEAR_ERROR_STATUS | \
+			TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_PRINTK(h,a,b,c) { \
+if (h) \
+printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \
+else \
+printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \
+}
+
+#pragma pack(1)
+
+/* Scatter Gather List Entry */
+typedef struct TAG_TW_SG_Entry {
+	unsigned long address;
+	u32 length;
+} TW_SG_Entry;
+
+/* Command Packet */
+typedef struct TW_Command {
+	/* First DWORD */
+	struct {
+		unsigned char opcode:5;
+		unsigned char sgl_offset:3;
+	} byte0_offset;
+	unsigned char size;
+	unsigned char request_id;
+	struct {
+		unsigned char unit:4;
+		unsigned char host_id:4;
+	} byte3_offset;
+	/* Second DWORD */
+	unsigned char status;
+	unsigned char flags;
+	union {
+		unsigned short block_count;
+		unsigned short parameter_count;
+	} byte6_offset;
+	union {
+		struct {
+			u32 lba;
+			TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+#if BITS_PER_LONG > 32
+			u32 padding[2];	/* pad to 512 bytes */
+#else
+			u32 padding;
+#endif
+		} io;
+		struct {
+			TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+#if BITS_PER_LONG > 32
+			u32 padding[3];
+#else
+			u32 padding[2];
+#endif
+		} param;
+	} byte8_offset;
+} TW_Command;
+
+/* Scatter gather element for 9000+ controllers */
+typedef struct TAG_TW_SG_Apache {
+	unsigned long address;
+	u32 length;
+} TW_SG_Apache;
+
+/* Command Packet for 9000+ controllers */
+typedef struct TAG_TW_Command_Apache {
+	struct {
+		unsigned char opcode:5;
+		unsigned char reserved:3;
+	} command;
+	unsigned char unit;
+	unsigned short request_id;
+	unsigned char status;
+	unsigned char sgl_offset;
+	unsigned short sgl_entries;
+	unsigned char cdb[16];
+	TW_SG_Apache sg_list[TW_APACHE_MAX_SGL_LENGTH];
+#if BITS_PER_LONG > 32
+	unsigned char padding[8];
+#endif
+} TW_Command_Apache;
+
+/* New command packet header */
+typedef struct TAG_TW_Command_Apache_Header {
+	unsigned char sense_data[TW_SENSE_DATA_LENGTH];
+	struct {
+		char reserved[4];
+		unsigned short error;
+		unsigned char padding;
+		struct {
+			unsigned char severity:3;
+			unsigned char reserved:5;
+		} substatus_block;
+	} status_block;
+	unsigned char err_specific_desc[98];
+	struct {
+		unsigned char size_header;
+		unsigned short reserved;
+		unsigned char size_sense;
+	} header_desc;
+} TW_Command_Apache_Header;
+
+/* This struct is a union of the 2 command packets */
+typedef struct TAG_TW_Command_Full {
+	TW_Command_Apache_Header header;
+	union {
+		TW_Command oldcommand;
+		TW_Command_Apache newcommand;
+	} command;
+} TW_Command_Full;
+
+/* Initconnection structure */
+typedef struct TAG_TW_Initconnect {
+	unsigned char opcode:5;
+	unsigned char res1:3;
+	unsigned char size;
+	unsigned char request_id;
+	unsigned char res2;
+	unsigned char status;
+	unsigned char flags;
+	unsigned short message_credits;
+	u32 features;
+	unsigned short fw_srl;
+	unsigned short fw_arch_id;
+	unsigned short fw_branch;
+	unsigned short fw_build;
+	u32 result;
+} TW_Initconnect;
+
+/* Event info structure */
+typedef struct TAG_TW_Event
+{
+	unsigned int sequence_id;
+	unsigned int time_stamp_sec;
+	unsigned short aen_code;
+	unsigned char severity;
+	unsigned char retrieved;
+	unsigned char repeat_count;
+	unsigned char parameter_len;
+	unsigned char parameter_data[98];
+} TW_Event;
+
+typedef struct TAG_TW_Ioctl_Driver_Command {
+	unsigned int control_code;
+	unsigned int status;
+	unsigned int unique_id;
+	unsigned int sequence_id;
+	unsigned int os_specific;
+	unsigned int buffer_length;
+} TW_Ioctl_Driver_Command;
+
+typedef struct TAG_TW_Ioctl_Apache {
+	TW_Ioctl_Driver_Command driver_command;
+        char padding[488];
+	TW_Command_Full firmware_command;
+	char data_buffer[1];
+} TW_Ioctl_Buf_Apache;
+
+/* Lock structure for ioctl get/release lock */
+typedef struct TAG_TW_Lock {
+	unsigned long timeout_msec;
+	unsigned long time_remaining_msec;
+	unsigned long force_flag;
+} TW_Lock;
+
+/* GetParam descriptor */
+typedef struct {
+	unsigned short	table_id;
+	unsigned short	parameter_id;
+	unsigned short	parameter_size_bytes;
+	unsigned short  actual_parameter_size_bytes;
+	unsigned char	data[1];
+} TW_Param_Apache, *PTW_Param_Apache;
+
+/* Response queue */
+typedef union TAG_TW_Response_Queue {
+	struct {
+		u32 undefined_1: 4;
+		u32 response_id: 8;
+		u32 undefined_2: 20;
+	} u;
+	u32 value;
+} TW_Response_Queue;
+
+typedef struct TAG_TW_Info {
+	char *buffer;
+	int length;
+	int offset;
+	int position;
+} TW_Info;
+
+/* Compatibility information structure */
+typedef struct TAG_TW_Compatibility_Info
+{
+	char driver_version[32];
+	unsigned short working_srl;
+	unsigned short working_branch;
+	unsigned short working_build;
+} TW_Compatibility_Info;
+
+/* Command header for ATA pass-thru */
+typedef struct TAG_TW_Passthru
+{
+	struct {
+		unsigned char opcode:5;
+		unsigned char sgloff:3;
+	} byte0;
+	unsigned char size;
+	unsigned char request_id;
+	struct {
+		unsigned char aport:4;
+		unsigned char host_id:4;
+	} byte3;
+	unsigned char status;
+	unsigned char flags;
+	unsigned short param;
+	unsigned short features;
+	unsigned short sector_count;
+	unsigned short sector_num;
+	unsigned short cylinder_lo;
+	unsigned short cylinder_hi;
+	unsigned char drive_head;
+	unsigned char command;
+	TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX];
+	unsigned char padding[12];
+} TW_Passthru;
+
+typedef struct TAG_TW_Device_Extension {
+	u32                     *base_addr;
+	unsigned long	       	*generic_buffer_virt[TW_Q_LENGTH];
+	unsigned long	       	generic_buffer_phys[TW_Q_LENGTH];
+	unsigned long	       	*command_packet_virt[TW_Q_LENGTH];
+	unsigned long		command_packet_phys[TW_Q_LENGTH];
+	struct pci_dev		*tw_pci_dev;
+	struct scsi_cmnd	*srb[TW_Q_LENGTH];
+	unsigned char		free_queue[TW_Q_LENGTH];
+	unsigned char		free_head;
+	unsigned char		free_tail;
+	unsigned char		pending_queue[TW_Q_LENGTH];
+	unsigned char		pending_head;
+	unsigned char		pending_tail;
+	int     		state[TW_Q_LENGTH];
+	unsigned int		posted_request_count;
+	unsigned int		max_posted_request_count;
+	unsigned int	        pending_request_count;
+	unsigned int		max_pending_request_count;
+	unsigned int		max_sgl_entries;
+	unsigned int		sgl_entries;
+	unsigned int		num_aborts;
+	unsigned int		num_resets;
+	unsigned int		sector_count;
+	unsigned int		max_sector_count;
+	unsigned int		aen_count;
+	struct Scsi_Host	*host;
+	long			flags;
+	int			reset_print;
+	TW_Event                *event_queue[TW_Q_LENGTH];
+	unsigned char           error_index;
+	unsigned char		event_queue_wrapped;
+	unsigned int            error_sequence_id;
+	int                     ioctl_sem_lock;
+	u32                     ioctl_msec;
+	int			chrdev_request_id;
+	wait_queue_head_t	ioctl_wqueue;
+	struct semaphore	ioctl_sem;
+	char			aen_clobber;
+	unsigned short		working_srl;
+	unsigned short		working_branch;
+	unsigned short		working_build;
+} TW_Device_Extension;
+
+#pragma pack()
+
+#endif /* _3W_9XXX_H */
+
--- diff/drivers/usb/core/sysfs.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/usb/core/sysfs.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,229 @@
+/*
+ * drivers/usb/core/sysfs.c
+ *
+ * (C) Copyright 2002 David Brownell
+ * (C) Copyright 2002 Greg Kroah-Hartman
+ * (C) Copyright 2002 IBM Corp.
+ *
+ * All of the sysfs file attributes for usb devices and interfaces.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb.h"
+
+/* Active configuration fields */
+#define usb_actconfig_show(field, multiplier, format_string)		\
+static ssize_t  show_##field (struct device *dev, char *buf)		\
+{									\
+	struct usb_device *udev;					\
+									\
+	udev = to_usb_device (dev);					\
+	if (udev->actconfig)						\
+		return sprintf (buf, format_string,			\
+				udev->actconfig->desc.field * multiplier);	\
+	else								\
+		return 0;						\
+}									\
+
+#define usb_actconfig_attr(field, multiplier, format_string)		\
+usb_actconfig_show(field, multiplier, format_string)			\
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr (bmAttributes, 1, "%2x\n")
+usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
+
+/* configuration value is always present, and r/w */
+usb_actconfig_show(bConfigurationValue, 1, "%u\n");
+
+static ssize_t
+set_bConfigurationValue (struct device *dev, const char *buf, size_t count)
+{
+	struct usb_device	*udev = udev = to_usb_device (dev);
+	int			config, value;
+
+	if (sscanf (buf, "%u", &config) != 1 || config > 255)
+		return -EINVAL;
+	down(&udev->serialize);
+	value = usb_set_configuration (udev, config);
+	up(&udev->serialize);
+	return (value < 0) ? value : count;
+}
+
+static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, 
+		show_bConfigurationValue, set_bConfigurationValue);
+
+/* String fields */
+#define usb_string_attr(name, field)		\
+static ssize_t  show_##name(struct device *dev, char *buf)		\
+{									\
+	struct usb_device *udev;					\
+	int len;							\
+									\
+	udev = to_usb_device (dev);					\
+	len = usb_string(udev, udev->descriptor.field, buf, PAGE_SIZE);	\
+	if (len < 0)							\
+		return 0;						\
+	buf[len] = '\n';						\
+	buf[len+1] = 0;							\
+	return len+1;							\
+}									\
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+
+usb_string_attr(product, iProduct);
+usb_string_attr(manufacturer, iManufacturer);
+usb_string_attr(serial, iSerialNumber);
+
+static ssize_t
+show_speed (struct device *dev, char *buf)
+{
+	struct usb_device *udev;
+	char *speed;
+
+	udev = to_usb_device (dev);
+
+	switch (udev->speed) {
+	case USB_SPEED_LOW:
+		speed = "1.5";
+		break;
+	case USB_SPEED_UNKNOWN:
+	case USB_SPEED_FULL:
+		speed = "12";
+		break;
+	case USB_SPEED_HIGH:
+		speed = "480";
+		break;
+	default:
+		speed = "unknown";
+	}
+	return sprintf (buf, "%s\n", speed);
+}
+static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
+
+static ssize_t
+show_devnum (struct device *dev, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device (dev);
+	return sprintf (buf, "%d\n", udev->devnum);
+}
+static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
+
+static ssize_t
+show_version (struct device *dev, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device (dev);
+	return sprintf (buf, "%2x.%02x\n", udev->descriptor.bcdUSB >> 8, 
+			udev->descriptor.bcdUSB & 0xff);
+}
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t
+show_maxchild (struct device *dev, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device (dev);
+	return sprintf (buf, "%d\n", udev->maxchild);
+}
+static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
+
+/* Descriptor fields */
+#define usb_descriptor_attr(field, format_string)			\
+static ssize_t								\
+show_##field (struct device *dev, char *buf)				\
+{									\
+	struct usb_device *udev;					\
+									\
+	udev = to_usb_device (dev);					\
+	return sprintf (buf, format_string, udev->descriptor.field);	\
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+usb_descriptor_attr (idVendor, "%04x\n")
+usb_descriptor_attr (idProduct, "%04x\n")
+usb_descriptor_attr (bcdDevice, "%04x\n")
+usb_descriptor_attr (bDeviceClass, "%02x\n")
+usb_descriptor_attr (bDeviceSubClass, "%02x\n")
+usb_descriptor_attr (bDeviceProtocol, "%02x\n")
+usb_descriptor_attr (bNumConfigurations, "%d\n")
+
+
+void usb_create_sysfs_dev_files (struct usb_device *udev)
+{
+	struct device *dev = &udev->dev;
+
+	/* current configuration's attributes */
+	device_create_file (dev, &dev_attr_bNumInterfaces);
+	device_create_file (dev, &dev_attr_bConfigurationValue);
+	device_create_file (dev, &dev_attr_bmAttributes);
+	device_create_file (dev, &dev_attr_bMaxPower);
+
+	/* device attributes */
+	device_create_file (dev, &dev_attr_idVendor);
+	device_create_file (dev, &dev_attr_idProduct);
+	device_create_file (dev, &dev_attr_bcdDevice);
+	device_create_file (dev, &dev_attr_bDeviceClass);
+	device_create_file (dev, &dev_attr_bDeviceSubClass);
+	device_create_file (dev, &dev_attr_bDeviceProtocol);
+	device_create_file (dev, &dev_attr_bNumConfigurations);
+
+	/* speed varies depending on how you connect the device */
+	device_create_file (dev, &dev_attr_speed);
+	// FIXME iff there are other speed configs, show how many
+
+	if (udev->descriptor.iManufacturer)
+		device_create_file (dev, &dev_attr_manufacturer);
+	if (udev->descriptor.iProduct)
+		device_create_file (dev, &dev_attr_product);
+	if (udev->descriptor.iSerialNumber)
+		device_create_file (dev, &dev_attr_serial);
+
+	device_create_file (dev, &dev_attr_devnum);
+	device_create_file (dev, &dev_attr_version);
+	device_create_file (dev, &dev_attr_maxchild);
+}
+
+/* Interface fields */
+#define usb_intf_attr(field, format_string)				\
+static ssize_t								\
+show_##field (struct device *dev, char *buf)				\
+{									\
+	struct usb_interface *intf = to_usb_interface (dev);		\
+									\
+	return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+usb_intf_attr (bInterfaceNumber, "%02x\n")
+usb_intf_attr (bAlternateSetting, "%2d\n")
+usb_intf_attr (bNumEndpoints, "%02x\n")
+usb_intf_attr (bInterfaceClass, "%02x\n")
+usb_intf_attr (bInterfaceSubClass, "%02x\n")
+usb_intf_attr (bInterfaceProtocol, "%02x\n")
+usb_intf_attr (iInterface, "%02x\n")
+
+void usb_create_sysfs_intf_files (struct usb_interface *intf)
+{
+	device_create_file (&intf->dev, &dev_attr_bInterfaceNumber);
+	device_create_file (&intf->dev, &dev_attr_bAlternateSetting);
+	device_create_file (&intf->dev, &dev_attr_bNumEndpoints);
+	device_create_file (&intf->dev, &dev_attr_bInterfaceClass);
+	device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass);
+	device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol);
+	device_create_file (&intf->dev, &dev_attr_iInterface);
+}
--- diff/include/asm-alpha/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-alpha/lockmeter.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,84 @@
+/*
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Peter Rival (frival@zk3.dec.com)
+ */
+
+#ifndef _ALPHA_LOCKMETER_H
+#define _ALPHA_LOCKMETER_H
+
+#include <asm/hwrpb.h>
+#define CPU_CYCLE_FREQUENCY	hwrpb->cycle_freq
+
+#define get_cycles64()		get_cycles()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+#include <linux/version.h>
+
+#define SPINLOCK_MAGIC_INIT /**/
+
+/*
+ * Macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * We also assume that the hash table has less than 32767 entries.
+ * the high order bit is used for write locking a rw_lock
+ * Note: although these defines and macros are the same as what is being used
+ *       in include/asm-i386/lockmeter.h, they are present here to easily
+ *	 allow an alternate Alpha implementation.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Alpha is little endian */
+	unsigned short lock;
+	unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv)	((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)		((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv)	((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)		((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)	((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)		((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) (((inst_rwlock_t *)rwlock_ptr)->lock & 1)
+#define IABS(x) ((x) > 0 ? (x) : -(x))
+
+#define RWLOCK_READERS(rwlock_ptr)	rwlock_readers(rwlock_ptr)
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) ((inst_rwlock_t *)rwlock_ptr)->lock;
+	/* readers subtract 2, so we have to:		*/
+	/* 	- andnot off a possible writer (bit 0)	*/
+	/*	- get the absolute value		*/
+	/*	- divide by 2 (right shift by one)	*/
+	/* to find the number of readers		*/
+	if (tmp == 0) return(0);
+	else return(IABS(tmp & ~1)>>1);
+}
+
+#endif /* _ALPHA_LOCKMETER_H */
--- diff/include/asm-alpha/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-alpha/setup.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef __ALPHA_SETUP_H
+#define __ALPHA_SETUP_H
+
+#define COMMAND_LINE_SIZE	256
+
+#endif
--- diff/include/asm-i386/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/kgdb.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,69 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm("   int $3")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, int err_code, struct pt_regs *regs);
+extern int in_kgdb(struct pt_regs *regs);
+
+#ifdef CONFIG_KGDB_TS
+void kgdb_tstamp(int line, char *source, int data0, int data1);
+/*
+ * This is the time stamp function.  The macro adds the source info and
+ * does a cast on the data to allow most any 32-bit value.
+ */
+
+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
+#else
+#define kgdb_ts(data0,data1)
+#endif
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-i386/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/kgdb_local.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x3f8
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#endif
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+#ifndef CONFIG_X86_TSC
+#undef rdtsc
+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
+#undef rdtscll
+#define rdtscll(s) s++
+#endif
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
+                                   "pushl %0 ; popfl": \
+                                     /* no output */ :"g" (x):"memory", "cc")
+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/asm-i386/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/lockmeter.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks.
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code here from include/lockmeter.h.
+ *
+ */
+
+#ifndef _I386_LOCKMETER_H
+#define _I386_LOCKMETER_H
+
+#include <asm/spinlock.h>
+#include <asm/rwlock.h>
+
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+extern unsigned long cpu_khz;
+#define CPU_CYCLE_FREQUENCY	(cpu_khz * 1000)
+#else
+#define CPU_CYCLE_FREQUENCY	450000000
+#endif
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a spin lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.  Not normally a problem!!
+ * we also assume that the hash table has less than 65535 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Intel is little endian */
+	unsigned short lock;
+	unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) rwlock_ptr->lock;
+	/* read and write lock attempts may cause the lock value to temporarily */
+	/* be negative.  Until it is >= 0 we know nothing (i. e. can't tell if  */
+	/* is -1 because it was write locked and somebody tried to read lock it */
+	/* or if it is -1 because it was read locked and somebody tried to write*/
+	/* lock it. ........................................................... */
+	do {
+		tmp = (int) rwlock_ptr->lock;
+	} while (tmp < 0);
+	if (tmp == 0) return(0);
+	else return(RW_LOCK_BIAS-tmp);
+}
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock <= 0)
+#define IABS(x) ((x) > 0 ? (x) : -(x))
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((IABS((rwlock_ptr)->lock) % RW_LOCK_BIAS) != 0)
+
+/* this is a lot of typing just to get gcc to emit "rdtsc" */
+static inline long long get_cycles64 (void)
+{
+	union longlong_u {
+		long long intlong;
+		struct intint_s {
+			uint32_t eax;
+			uint32_t edx;
+		} intint;
+	} longlong;
+
+	rdtsc(longlong.intint.eax,longlong.intint.edx);
+	return longlong.intlong;
+}
+
+#endif /* _I386_LOCKMETER_H */
--- diff/include/asm-ia64/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/kgdb.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,69 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm volatile ("break.m 0x6665")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+struct kgdb_serial {
+	unsigned long	iobase;
+	unsigned long	shift;
+	int		line;
+	int		iotype;
+	int		claimed;
+};
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, unsigned long err_code, struct pt_regs *regs);
+struct unw_frame_info;
+extern int in_kgdb(struct pt_regs *regs, struct unw_frame_info *);
+#ifdef	CONFIG_KGDB_EARLY
+extern void __init kgdb_serial_init(void);
+#endif
+
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define in_kgdb
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-ia64/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/kgdb_local.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,114 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x0
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#define IOTYPE SERIAL_IO_PORT
+#endif
+
+#define	IOMEM 0x0
+#ifdef	CONFIG_KGDB_IOMEM
+#undef	IOMEM
+#define	IOMEM CONFIG_KGDB_IOMEM
+#define	IOTYPE SERIAL_IO_MEM
+#endif
+
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+
+#define	IOMEM_REG_SHIFT 0
+#ifdef	CONFIG_IOMEM_REG_SHIFT
+#undef	IOMEM_REG_SHIFT
+#define	IOMEM_REG_SHIFT CONFIG_IOMEM_REG_SHIFT
+#endif
+
+
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     iomem_base:(u8 *) IOMEM,    \
+     iomem_reg_shift: IOMEM_REG_SHIFT,\
+     io_type: IOTYPE,	\
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      io_type: IOTYPE,	   \
+      iomem_base: (u8 *) IOMEM,   \
+      iomem_reg_shift: IOMEM_REG_SHIFT, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_local_save_flags(x) 	local_save_flags(x)
+#define kgdb_local_irq_restore(x) 	local_irq_restore(x)
+#define kgdb_local_irq_save(x) 		local_irq_save(x)
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+extern void kgdb_serial_setup(struct uart_port *);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/asm-ia64/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/lockmeter.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ */
+
+#ifndef _IA64_LOCKMETER_H
+#define _IA64_LOCKMETER_H
+
+#ifdef local_cpu_data
+#define CPU_CYCLE_FREQUENCY	local_cpu_data->itc_freq
+#else
+#define CPU_CYCLE_FREQUENCY	my_cpu_data.itc_freq
+#endif
+#define get_cycles64()		get_cycles()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * we also assume that the hash table has less than 32767 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Intel is little endian */
+	volatile unsigned short lock;
+	volatile unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int read_counter:31;
+	volatile int write_lock:1;
+	volatile unsigned short index;
+	volatile unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)	((rwlock_ptr)->read_counter)
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->write_lock)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->read_counter)
+
+#endif /* _IA64_LOCKMETER_H */
+
--- diff/include/asm-ia64/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/setup.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef __IA64_SETUP_H
+#define __IA64_SETUP_H
+
+#define COMMAND_LINE_SIZE	512
+
+#endif
--- diff/include/asm-mips/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-mips/lockmeter.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,126 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *  Ported to mips32 for Asita Technologies
+ *   by D.J. Barrow ( dj.barrow@asitatechnologies.com )
+ */
+#ifndef _ASM_LOCKMETER_H
+#define _ASM_LOCKMETER_H
+
+/* do_gettimeoffset is a function pointer on mips */
+/* & it is not included by <linux/time.h> */
+#include <asm/time.h>
+#include <linux/time.h>
+#include <asm/div64.h>
+
+#define SPINLOCK_MAGIC_INIT	/* */
+
+#define CPU_CYCLE_FREQUENCY	get_cpu_cycle_frequency()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+static uint32_t cpu_cycle_frequency = 0;
+
+static uint32_t get_cpu_cycle_frequency(void)
+{
+    /* a total hack, slow and invasive, but ... it works */
+    int sec;
+    uint32_t start_cycles;
+    struct timeval tv;
+
+    if (cpu_cycle_frequency == 0) {	/* uninitialized */
+	do_gettimeofday(&tv);
+	sec = tv.tv_sec;	/* set up to catch the tv_sec rollover */
+	while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
+	sec = tv.tv_sec;	/* rolled over to a new sec value */
+	start_cycles = get_cycles();
+	while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
+	cpu_cycle_frequency = get_cycles() - start_cycles;
+    }
+
+    return cpu_cycle_frequency;
+}
+
+extern struct timeval xtime;
+
+static uint64_t get_cycles64(void)
+{
+    static uint64_t last_get_cycles64 = 0;
+    uint64_t ret;
+    unsigned long sec;
+    unsigned long usec, usec_offset;
+
+again:
+    sec  = xtime.tv_sec;
+    usec = xtime.tv_usec;
+    usec_offset = do_gettimeoffset();
+    if ((xtime.tv_sec != sec)  ||
+	(xtime.tv_usec != usec)||
+	(usec_offset >= 20000))
+	goto again;
+
+    ret = ((uint64_t)(usec + usec_offset) * cpu_cycle_frequency);
+    /* We can't do a normal 64 bit division on mips without libgcc.a */
+    do_div(ret,1000000);
+    ret +=  ((uint64_t)sec * cpu_cycle_frequency);
+
+    /* XXX why does time go backwards?  do_gettimeoffset?  general time adj? */
+    if (ret <= last_get_cycles64)
+	ret  = last_get_cycles64+1;
+    last_get_cycles64 = ret;
+
+    return ret;
+}
+
+/*
+ * macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * we also assume that the hash table has less than 32767 entries.
+ * the high order bit is used for write locking a rw_lock
+ */
+#define INDEX_MASK   0x7FFF0000
+#define READERS_MASK 0x0000FFFF
+#define INDEX_SHIFT 16
+#define PUT_INDEX(lockp,index)   \
+        lockp->lock = (((lockp->lock) & ~INDEX_MASK) | (index) << INDEX_SHIFT)
+#define GET_INDEX(lockp) \
+        (((lockp->lock) & INDEX_MASK) >> INDEX_SHIFT)
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) rwlock_ptr->lock;
+	return (tmp >= 0) ? tmp : 0;
+}
+
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->lock > 0)
+
+#endif /* _ASM_LOCKMETER_H */
--- diff/include/asm-mips/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-mips/setup.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,8 @@
+#ifdef __KERNEL__
+#ifndef _MIPS_SETUP_H
+#define _MIPS_SETUP_H
+
+#define COMMAND_LINE_SIZE	256
+
+#endif /* __SETUP_H */
+#endif /* __KERNEL__ */
--- diff/include/asm-sh/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-sh/setup.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,8 @@
+#ifdef __KERNEL__
+#ifndef _SH_SETUP_H
+#define _SH_SETUP_H
+
+#define COMMAND_LINE_SIZE 256
+
+#endif /* _SH_SETUP_H */
+#endif /* __KERNEL__ */
--- diff/include/asm-sparc64/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-sparc64/lockmeter.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef _SPARC64_LOCKMETER_H
+#define _SPARC64_LOCKMETER_H
+
+#include <linux/smp.h>
+#include <asm/spinlock.h>
+#include <asm/timer.h>
+#include <asm/timex.h>
+
+/* Actually, this is not the CPU frequency by the system tick
+ * frequency which is good enough for lock metering.
+ */
+#define CPU_CYCLE_FREQUENCY	(timer_tick_offset * HZ)
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+#define PUT_INDEX(lock_ptr,indexv)	(lock_ptr)->index = (indexv)
+#define GET_INDEX(lock_ptr)		(lock_ptr)->index
+
+#define PUT_RWINDEX(rwlock_ptr,indexv) (rwlock_ptr)->index = (indexv)
+#define GET_RWINDEX(rwlock_ptr)        (rwlock_ptr)->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    (rwlock_ptr)->cpu = (cpuv)
+#define GET_RW_CPU(rwlock_ptr)         (rwlock_ptr)->cpu
+
+#define RWLOCK_READERS(rwlock_ptr)	rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	signed int tmp = rwlock_ptr->lock;
+
+	if (tmp > 0)
+		return tmp;
+	else
+		return 0;
+}
+
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr)	((signed int)((rwlock_ptr)->lock) < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)	((signed int)((rwlock_ptr)->lock) > 0)
+
+#define get_cycles64()	get_cycles()
+
+#endif /* _SPARC64_LOCKMETER_H */
--- diff/include/asm-um/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-um/setup.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef SETUP_H_INCLUDED
+#define SETUP_H_INCLUDED
+
+#define COMMAND_LINE_SIZE 512
+
+#endif		/* SETUP_H_INCLUDED */
--- diff/include/asm-v850/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-v850/setup.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef _V850_SETUP_H
+#define _V850_SETUP_H
+
+#define COMMAND_LINE_SIZE	512
+
+#endif /* __SETUP_H */
--- diff/include/asm-x86_64/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/kgdb.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,71 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm("   int $3")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, int err_code, struct pt_regs *regs);
+extern int in_kgdb(struct pt_regs *regs);
+
+extern void set_debug_traps(void);
+
+#ifdef CONFIG_KGDB_TS
+void kgdb_tstamp(int line, char *source, int data0, int data1);
+/*
+ * This is the time stamp function.  The macro adds the source info and
+ * does a cast on the data to allow most any 32-bit value.
+ */
+
+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
+#else
+#define kgdb_ts(data0,data1)
+#endif
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb	(0)
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-x86_64/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/kgdb_local.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x3f8
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#endif
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+#ifndef CONFIG_X86_TSC
+#undef rdtsc
+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
+#undef rdtscll
+#define rdtscll(s) s++
+#endif
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
+                                   "pushl %0 ; popfl": \
+                                     /* no output */ :"g" (x):"memory", "cc")
+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/linux/dwarf2-lang.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dwarf2-lang.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,132 @@
+#ifndef DWARF2_LANG
+#define DWARF2_LANG
+#include <linux/dwarf2.h>
+
+/*
+ * This 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.
+ */
+/*
+ * This file defines macros that allow generation of DWARF debug records
+ * for asm files.  This file is platform independent.  Register numbers
+ * (which are about the only thing that is platform dependent) are to be
+ * supplied by a platform defined file.
+ */
+#define DWARF_preamble()	.section	.debug_frame,"",@progbits
+/*
+ * This macro starts a debug frame section.  The debug_frame describes
+ * where to find the registers that the enclosing function saved on
+ * entry.
+ *
+ * ORD is use by the label generator and should be the same as what is
+ * passed to CFI_postamble.
+ *
+ * pc,	pc register gdb ordinal.
+ *
+ * code_align this is the factor used to define locations or regions
+ * where the given definitions apply.  If you use labels to define these
+ * this should be 1.
+ *
+ * data_align this is the factor used to define register offsets.  If
+ * you use struct offset, this should be the size of the register in
+ * bytes or the negative of that.  This is how it is used: you will
+ * define a register as the reference register, say the stack pointer,
+ * then you will say where a register is located relative to this
+ * reference registers value, say 40 for register 3 (the gdb register
+ * number).  The <40> will be multiplied by <data_align> to define the
+ * byte offset of the given register (3, in this example).  So if your
+ * <40> is the byte offset and the reference register points at the
+ * begining, you would want 1 for the data_offset.  If <40> was the 40th
+ * 4-byte element in that structure you would want 4.  And if your
+ * reference register points at the end of the structure you would want
+ * a negative data_align value(and you would have to do other math as
+ * well).
+ */
+
+#define CFI_preamble(ORD, pc, code_align, data_align)	\
+.section	.debug_frame,"",@progbits ;		\
+frame/**/_/**/ORD:						\
+	.long end/**/_/**/ORD-start/**/_/**/ORD;			\
+start/**/_/**/ORD:						\
+	.long	DW_CIE_ID;				\
+	.byte	DW_CIE_VERSION;			\
+	.byte 0	 ;				\
+	.uleb128 code_align;				\
+	.sleb128 data_align;				\
+	.byte pc;
+
+/*
+ * After the above macro and prior to the CFI_postamble, you need to
+ * define the initial state.  This starts with defining the reference
+ * register and, usually the pc.  Here are some helper macros:
+ */
+
+#define CFA_define_reference(reg, offset)	\
+	.byte DW_CFA_def_cfa;			\
+	.uleb128 reg;				\
+	.uleb128 (offset);
+
+#define CFA_define_offset(reg, offset)		\
+	.byte (DW_CFA_offset + reg);		\
+	.uleb128 (offset);
+
+#define CFI_postamble(ORD)			\
+	.align 4;				\
+end/**/_/**/ORD:
+/*
+ * So now your code pushs stuff on the stack, you need a new location
+ * and the rules for what to do.  This starts a running description of
+ * the call frame.  You need to describe what changes with respect to
+ * the call registers as the location of the pc moves through the code.
+ * The following builds an FDE (fram descriptor entry?).  Like the
+ * above, it has a preamble and a postamble.  It also is tied to the CFI
+ * above.
+ * The first entry after the preamble must be the location in the code
+ * that the call frame is being described for.
+ */
+#define FDE_preamble(ORD, fde_no, initial_address, length)	\
+	.long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no;		\
+FDE_start/**/_/**/fde_no:						\
+	.long frame/**/_/**/ORD;					\
+	.long initial_address;					\
+	.long length;
+
+#define FDE_postamble(fde_no)			\
+	.align 4;				\
+FDE_end/**/_/**/fde_no:
+/*
+ * That done, you can now add registers, subtract registers, move the
+ * reference and even change the reference.  You can also define a new
+ * area of code the info applies to.  For discontinuous bits you should
+ * start a new FDE.  You may have as many as you like.
+ */
+
+/*
+ * To advance the address by <bytes>
+ */
+
+#define FDE_advance(bytes)			\
+	.byte DW_CFA_advance_loc4		\
+	.long bytes
+
+
+
+/*
+ * With the above you can define all the register locations.  But
+ * suppose the reference register moves... Takes the new offset NOT an
+ * increment.  This is how esp is tracked if it is not saved.
+ */
+
+#define CFA_define_cfa_offset(offset) \
+	.byte $DW_CFA_def_cfa_offset; \
+	.uleb128 (offset);
+/*
+ * Or suppose you want to use a different reference register...
+ */
+#define CFA_define_cfa_register(reg)		\
+	.byte DW_CFA_def_cfa_register;		\
+	.uleb128 reg;
+
+#endif
--- diff/include/linux/dwarf2.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dwarf2.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,738 @@
+/* Declarations and definitions of codes relating to the DWARF2 symbolic
+   debugging information format.
+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
+
+   Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
+   Office (AJPO), Florida State Unviversity and Silicon Graphics Inc.
+   provided support for this effort -- June 21, 1995.
+
+   Derived from the DWARF 1 implementation written by Ron Guilmette
+   (rfg@netcom.com), November 1990.
+
+   This file is part of GCC.
+
+   GCC 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.
+
+   GCC 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 GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This file is derived from the DWARF specification (a public document)
+   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
+   Programming Languages Special Interest Group (UI/PLSIG) and distributed
+   by UNIX International.  Copies of this specification are available from
+   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+
+   This file also now contains definitions from the DWARF 3 specification.  */
+
+/* This file is shared between GCC and GDB, and should not contain
+   prototypes.	*/
+
+#ifndef _ELF_DWARF2_H
+#define _ELF_DWARF2_H
+
+/* Structure found in the .debug_line section.	*/
+#ifndef __ASSEMBLY__
+typedef struct
+{
+  unsigned char li_length	   [4];
+  unsigned char li_version	   [2];
+  unsigned char li_prologue_length [4];
+  unsigned char li_min_insn_length [1];
+  unsigned char li_default_is_stmt [1];
+  unsigned char li_line_base	   [1];
+  unsigned char li_line_range	   [1];
+  unsigned char li_opcode_base	   [1];
+}
+DWARF2_External_LineInfo;
+
+typedef struct
+{
+  unsigned long  li_length;
+  unsigned short li_version;
+  unsigned int	 li_prologue_length;
+  unsigned char  li_min_insn_length;
+  unsigned char  li_default_is_stmt;
+  int		 li_line_base;
+  unsigned char  li_line_range;
+  unsigned char  li_opcode_base;
+}
+DWARF2_Internal_LineInfo;
+
+/* Structure found in .debug_pubnames section.	*/
+typedef struct
+{
+  unsigned char pn_length  [4];
+  unsigned char pn_version [2];
+  unsigned char pn_offset  [4];
+  unsigned char pn_size    [4];
+}
+DWARF2_External_PubNames;
+
+typedef struct
+{
+  unsigned long  pn_length;
+  unsigned short pn_version;
+  unsigned long  pn_offset;
+  unsigned long  pn_size;
+}
+DWARF2_Internal_PubNames;
+
+/* Structure found in .debug_info section.  */
+typedef struct
+{
+  unsigned char  cu_length	  [4];
+  unsigned char  cu_version	  [2];
+  unsigned char  cu_abbrev_offset [4];
+  unsigned char  cu_pointer_size  [1];
+}
+DWARF2_External_CompUnit;
+
+typedef struct
+{
+  unsigned long  cu_length;
+  unsigned short cu_version;
+  unsigned long  cu_abbrev_offset;
+  unsigned char  cu_pointer_size;
+}
+DWARF2_Internal_CompUnit;
+
+typedef struct
+{
+  unsigned char  ar_length	 [4];
+  unsigned char  ar_version	 [2];
+  unsigned char  ar_info_offset  [4];
+  unsigned char  ar_pointer_size [1];
+  unsigned char  ar_segment_size [1];
+}
+DWARF2_External_ARange;
+
+typedef struct
+{
+  unsigned long  ar_length;
+  unsigned short ar_version;
+  unsigned long  ar_info_offset;
+  unsigned char  ar_pointer_size;
+  unsigned char  ar_segment_size;
+}
+DWARF2_Internal_ARange;
+
+#define ENUM(name) enum name {
+#define IF_NOT_ASM(a) a
+#define COMMA ,
+#else
+#define ENUM(name)
+#define IF_NOT_ASM(a)
+#define COMMA
+
+#endif
+
+/* Tag names and codes.  */
+ENUM(dwarf_tag)
+
+    DW_TAG_padding = 0x00 COMMA
+    DW_TAG_array_type = 0x01 COMMA
+    DW_TAG_class_type = 0x02 COMMA
+    DW_TAG_entry_point = 0x03 COMMA
+    DW_TAG_enumeration_type = 0x04 COMMA
+    DW_TAG_formal_parameter = 0x05 COMMA
+    DW_TAG_imported_declaration = 0x08 COMMA
+    DW_TAG_label = 0x0a COMMA
+    DW_TAG_lexical_block = 0x0b COMMA
+    DW_TAG_member = 0x0d COMMA
+    DW_TAG_pointer_type = 0x0f COMMA
+    DW_TAG_reference_type = 0x10 COMMA
+    DW_TAG_compile_unit = 0x11 COMMA
+    DW_TAG_string_type = 0x12 COMMA
+    DW_TAG_structure_type = 0x13 COMMA
+    DW_TAG_subroutine_type = 0x15 COMMA
+    DW_TAG_typedef = 0x16 COMMA
+    DW_TAG_union_type = 0x17 COMMA
+    DW_TAG_unspecified_parameters = 0x18 COMMA
+    DW_TAG_variant = 0x19 COMMA
+    DW_TAG_common_block = 0x1a COMMA
+    DW_TAG_common_inclusion = 0x1b COMMA
+    DW_TAG_inheritance = 0x1c COMMA
+    DW_TAG_inlined_subroutine = 0x1d COMMA
+    DW_TAG_module = 0x1e COMMA
+    DW_TAG_ptr_to_member_type = 0x1f COMMA
+    DW_TAG_set_type = 0x20 COMMA
+    DW_TAG_subrange_type = 0x21 COMMA
+    DW_TAG_with_stmt = 0x22 COMMA
+    DW_TAG_access_declaration = 0x23 COMMA
+    DW_TAG_base_type = 0x24 COMMA
+    DW_TAG_catch_block = 0x25 COMMA
+    DW_TAG_const_type = 0x26 COMMA
+    DW_TAG_constant = 0x27 COMMA
+    DW_TAG_enumerator = 0x28 COMMA
+    DW_TAG_file_type = 0x29 COMMA
+    DW_TAG_friend = 0x2a COMMA
+    DW_TAG_namelist = 0x2b COMMA
+    DW_TAG_namelist_item = 0x2c COMMA
+    DW_TAG_packed_type = 0x2d COMMA
+    DW_TAG_subprogram = 0x2e COMMA
+    DW_TAG_template_type_param = 0x2f COMMA
+    DW_TAG_template_value_param = 0x30 COMMA
+    DW_TAG_thrown_type = 0x31 COMMA
+    DW_TAG_try_block = 0x32 COMMA
+    DW_TAG_variant_part = 0x33 COMMA
+    DW_TAG_variable = 0x34 COMMA
+    DW_TAG_volatile_type = 0x35 COMMA
+    /* DWARF 3.  */
+    DW_TAG_dwarf_procedure = 0x36 COMMA
+    DW_TAG_restrict_type = 0x37 COMMA
+    DW_TAG_interface_type = 0x38 COMMA
+    DW_TAG_namespace = 0x39 COMMA
+    DW_TAG_imported_module = 0x3a COMMA
+    DW_TAG_unspecified_type = 0x3b COMMA
+    DW_TAG_partial_unit = 0x3c COMMA
+    DW_TAG_imported_unit = 0x3d COMMA
+    /* SGI/MIPS Extensions.  */
+    DW_TAG_MIPS_loop = 0x4081 COMMA
+    /* GNU extensions.	*/
+    DW_TAG_format_label = 0x4101 COMMA	/* For FORTRAN 77 and Fortran 90.  */
+    DW_TAG_function_template = 0x4102 COMMA	/* For C++.  */
+    DW_TAG_class_template = 0x4103 COMMA	/* For C++.  */
+    DW_TAG_GNU_BINCL = 0x4104 COMMA
+    DW_TAG_GNU_EINCL = 0x4105 COMMA
+    /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
+    DW_TAG_upc_shared_type = 0x8765 COMMA
+    DW_TAG_upc_strict_type = 0x8766 COMMA
+    DW_TAG_upc_relaxed_type = 0x8767
+IF_NOT_ASM(};)
+
+#define DW_TAG_lo_user	0x4080
+#define DW_TAG_hi_user	0xffff
+
+/* Flag that tells whether entry has a child or not.  */
+#define DW_children_no	 0
+#define	DW_children_yes  1
+
+/* Form names and codes.  */
+ENUM(dwarf_form)
+
+    DW_FORM_addr = 0x01 COMMA
+    DW_FORM_block2 = 0x03 COMMA
+    DW_FORM_block4 = 0x04 COMMA
+    DW_FORM_data2 = 0x05 COMMA
+    DW_FORM_data4 = 0x06 COMMA
+    DW_FORM_data8 = 0x07 COMMA
+    DW_FORM_string = 0x08 COMMA
+    DW_FORM_block = 0x09 COMMA
+    DW_FORM_block1 = 0x0a COMMA
+    DW_FORM_data1 = 0x0b COMMA
+    DW_FORM_flag = 0x0c COMMA
+    DW_FORM_sdata = 0x0d COMMA
+    DW_FORM_strp = 0x0e COMMA
+    DW_FORM_udata = 0x0f COMMA
+    DW_FORM_ref_addr = 0x10 COMMA
+    DW_FORM_ref1 = 0x11 COMMA
+    DW_FORM_ref2 = 0x12 COMMA
+    DW_FORM_ref4 = 0x13 COMMA
+    DW_FORM_ref8 = 0x14 COMMA
+    DW_FORM_ref_udata = 0x15 COMMA
+    DW_FORM_indirect = 0x16
+IF_NOT_ASM(};)
+
+/* Attribute names and codes.  */
+
+ENUM(dwarf_attribute)
+
+    DW_AT_sibling = 0x01 COMMA
+    DW_AT_location = 0x02 COMMA
+    DW_AT_name = 0x03 COMMA
+    DW_AT_ordering = 0x09 COMMA
+    DW_AT_subscr_data = 0x0a COMMA
+    DW_AT_byte_size = 0x0b COMMA
+    DW_AT_bit_offset = 0x0c COMMA
+    DW_AT_bit_size = 0x0d COMMA
+    DW_AT_element_list = 0x0f COMMA
+    DW_AT_stmt_list = 0x10 COMMA
+    DW_AT_low_pc = 0x11 COMMA
+    DW_AT_high_pc = 0x12 COMMA
+    DW_AT_language = 0x13 COMMA
+    DW_AT_member = 0x14 COMMA
+    DW_AT_discr = 0x15 COMMA
+    DW_AT_discr_value = 0x16 COMMA
+    DW_AT_visibility = 0x17 COMMA
+    DW_AT_import = 0x18 COMMA
+    DW_AT_string_length = 0x19 COMMA
+    DW_AT_common_reference = 0x1a COMMA
+    DW_AT_comp_dir = 0x1b COMMA
+    DW_AT_const_value = 0x1c COMMA
+    DW_AT_containing_type = 0x1d COMMA
+    DW_AT_default_value = 0x1e COMMA
+    DW_AT_inline = 0x20 COMMA
+    DW_AT_is_optional = 0x21 COMMA
+    DW_AT_lower_bound = 0x22 COMMA
+    DW_AT_producer = 0x25 COMMA
+    DW_AT_prototyped = 0x27 COMMA
+    DW_AT_return_addr = 0x2a COMMA
+    DW_AT_start_scope = 0x2c COMMA
+    DW_AT_stride_size = 0x2e COMMA
+    DW_AT_upper_bound = 0x2f COMMA
+    DW_AT_abstract_origin = 0x31 COMMA
+    DW_AT_accessibility = 0x32 COMMA
+    DW_AT_address_class = 0x33 COMMA
+    DW_AT_artificial = 0x34 COMMA
+    DW_AT_base_types = 0x35 COMMA
+    DW_AT_calling_convention = 0x36 COMMA
+    DW_AT_count = 0x37 COMMA
+    DW_AT_data_member_location = 0x38 COMMA
+    DW_AT_decl_column = 0x39 COMMA
+    DW_AT_decl_file = 0x3a COMMA
+    DW_AT_decl_line = 0x3b COMMA
+    DW_AT_declaration = 0x3c COMMA
+    DW_AT_discr_list = 0x3d COMMA
+    DW_AT_encoding = 0x3e COMMA
+    DW_AT_external = 0x3f COMMA
+    DW_AT_frame_base = 0x40 COMMA
+    DW_AT_friend = 0x41 COMMA
+    DW_AT_identifier_case = 0x42 COMMA
+    DW_AT_macro_info = 0x43 COMMA
+    DW_AT_namelist_items = 0x44 COMMA
+    DW_AT_priority = 0x45 COMMA
+    DW_AT_segment = 0x46 COMMA
+    DW_AT_specification = 0x47 COMMA
+    DW_AT_static_link = 0x48 COMMA
+    DW_AT_type = 0x49 COMMA
+    DW_AT_use_location = 0x4a COMMA
+    DW_AT_variable_parameter = 0x4b COMMA
+    DW_AT_virtuality = 0x4c COMMA
+    DW_AT_vtable_elem_location = 0x4d COMMA
+    /* DWARF 3 values.	*/
+    DW_AT_allocated	= 0x4e COMMA
+    DW_AT_associated	= 0x4f COMMA
+    DW_AT_data_location = 0x50 COMMA
+    DW_AT_stride	= 0x51 COMMA
+    DW_AT_entry_pc	= 0x52 COMMA
+    DW_AT_use_UTF8	= 0x53 COMMA
+    DW_AT_extension	= 0x54 COMMA
+    DW_AT_ranges	= 0x55 COMMA
+    DW_AT_trampoline	= 0x56 COMMA
+    DW_AT_call_column	= 0x57 COMMA
+    DW_AT_call_file	= 0x58 COMMA
+    DW_AT_call_line	= 0x59 COMMA
+    /* SGI/MIPS extensions.  */
+    DW_AT_MIPS_fde = 0x2001 COMMA
+    DW_AT_MIPS_loop_begin = 0x2002 COMMA
+    DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA
+    DW_AT_MIPS_epilog_begin = 0x2004 COMMA
+    DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA
+    DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA
+    DW_AT_MIPS_linkage_name = 0x2007 COMMA
+    DW_AT_MIPS_stride = 0x2008 COMMA
+    DW_AT_MIPS_abstract_name = 0x2009 COMMA
+    DW_AT_MIPS_clone_origin = 0x200a COMMA
+    DW_AT_MIPS_has_inlines = 0x200b COMMA
+    /* GNU extensions.	*/
+    DW_AT_sf_names   = 0x2101 COMMA
+    DW_AT_src_info   = 0x2102 COMMA
+    DW_AT_mac_info   = 0x2103 COMMA
+    DW_AT_src_coords = 0x2104 COMMA
+    DW_AT_body_begin = 0x2105 COMMA
+    DW_AT_body_end   = 0x2106 COMMA
+    DW_AT_GNU_vector = 0x2107 COMMA
+    /* VMS extensions.	*/
+    DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA
+    /* UPC extension.  */
+    DW_AT_upc_threads_scaled = 0x3210
+IF_NOT_ASM(};)
+
+#define DW_AT_lo_user	0x2000	/* Implementation-defined range start.	*/
+#define DW_AT_hi_user	0x3ff0	/* Implementation-defined range end.  */
+
+/* Location atom names and codes.  */
+ENUM(dwarf_location_atom)
+
+    DW_OP_addr = 0x03 COMMA
+    DW_OP_deref = 0x06 COMMA
+    DW_OP_const1u = 0x08 COMMA
+    DW_OP_const1s = 0x09 COMMA
+    DW_OP_const2u = 0x0a COMMA
+    DW_OP_const2s = 0x0b COMMA
+    DW_OP_const4u = 0x0c COMMA
+    DW_OP_const4s = 0x0d COMMA
+    DW_OP_const8u = 0x0e COMMA
+    DW_OP_const8s = 0x0f COMMA
+    DW_OP_constu = 0x10 COMMA
+    DW_OP_consts = 0x11 COMMA
+    DW_OP_dup = 0x12 COMMA
+    DW_OP_drop = 0x13 COMMA
+    DW_OP_over = 0x14 COMMA
+    DW_OP_pick = 0x15 COMMA
+    DW_OP_swap = 0x16 COMMA
+    DW_OP_rot = 0x17 COMMA
+    DW_OP_xderef = 0x18 COMMA
+    DW_OP_abs = 0x19 COMMA
+    DW_OP_and = 0x1a COMMA
+    DW_OP_div = 0x1b COMMA
+    DW_OP_minus = 0x1c COMMA
+    DW_OP_mod = 0x1d COMMA
+    DW_OP_mul = 0x1e COMMA
+    DW_OP_neg = 0x1f COMMA
+    DW_OP_not = 0x20 COMMA
+    DW_OP_or = 0x21 COMMA
+    DW_OP_plus = 0x22 COMMA
+    DW_OP_plus_uconst = 0x23 COMMA
+    DW_OP_shl = 0x24 COMMA
+    DW_OP_shr = 0x25 COMMA
+    DW_OP_shra = 0x26 COMMA
+    DW_OP_xor = 0x27 COMMA
+    DW_OP_bra = 0x28 COMMA
+    DW_OP_eq = 0x29 COMMA
+    DW_OP_ge = 0x2a COMMA
+    DW_OP_gt = 0x2b COMMA
+    DW_OP_le = 0x2c COMMA
+    DW_OP_lt = 0x2d COMMA
+    DW_OP_ne = 0x2e COMMA
+    DW_OP_skip = 0x2f COMMA
+    DW_OP_lit0 = 0x30 COMMA
+    DW_OP_lit1 = 0x31 COMMA
+    DW_OP_lit2 = 0x32 COMMA
+    DW_OP_lit3 = 0x33 COMMA
+    DW_OP_lit4 = 0x34 COMMA
+    DW_OP_lit5 = 0x35 COMMA
+    DW_OP_lit6 = 0x36 COMMA
+    DW_OP_lit7 = 0x37 COMMA
+    DW_OP_lit8 = 0x38 COMMA
+    DW_OP_lit9 = 0x39 COMMA
+    DW_OP_lit10 = 0x3a COMMA
+    DW_OP_lit11 = 0x3b COMMA
+    DW_OP_lit12 = 0x3c COMMA
+    DW_OP_lit13 = 0x3d COMMA
+    DW_OP_lit14 = 0x3e COMMA
+    DW_OP_lit15 = 0x3f COMMA
+    DW_OP_lit16 = 0x40 COMMA
+    DW_OP_lit17 = 0x41 COMMA
+    DW_OP_lit18 = 0x42 COMMA
+    DW_OP_lit19 = 0x43 COMMA
+    DW_OP_lit20 = 0x44 COMMA
+    DW_OP_lit21 = 0x45 COMMA
+    DW_OP_lit22 = 0x46 COMMA
+    DW_OP_lit23 = 0x47 COMMA
+    DW_OP_lit24 = 0x48 COMMA
+    DW_OP_lit25 = 0x49 COMMA
+    DW_OP_lit26 = 0x4a COMMA
+    DW_OP_lit27 = 0x4b COMMA
+    DW_OP_lit28 = 0x4c COMMA
+    DW_OP_lit29 = 0x4d COMMA
+    DW_OP_lit30 = 0x4e COMMA
+    DW_OP_lit31 = 0x4f COMMA
+    DW_OP_reg0 = 0x50 COMMA
+    DW_OP_reg1 = 0x51 COMMA
+    DW_OP_reg2 = 0x52 COMMA
+    DW_OP_reg3 = 0x53 COMMA
+    DW_OP_reg4 = 0x54 COMMA
+    DW_OP_reg5 = 0x55 COMMA
+    DW_OP_reg6 = 0x56 COMMA
+    DW_OP_reg7 = 0x57 COMMA
+    DW_OP_reg8 = 0x58 COMMA
+    DW_OP_reg9 = 0x59 COMMA
+    DW_OP_reg10 = 0x5a COMMA
+    DW_OP_reg11 = 0x5b COMMA
+    DW_OP_reg12 = 0x5c COMMA
+    DW_OP_reg13 = 0x5d COMMA
+    DW_OP_reg14 = 0x5e COMMA
+    DW_OP_reg15 = 0x5f COMMA
+    DW_OP_reg16 = 0x60 COMMA
+    DW_OP_reg17 = 0x61 COMMA
+    DW_OP_reg18 = 0x62 COMMA
+    DW_OP_reg19 = 0x63 COMMA
+    DW_OP_reg20 = 0x64 COMMA
+    DW_OP_reg21 = 0x65 COMMA
+    DW_OP_reg22 = 0x66 COMMA
+    DW_OP_reg23 = 0x67 COMMA
+    DW_OP_reg24 = 0x68 COMMA
+    DW_OP_reg25 = 0x69 COMMA
+    DW_OP_reg26 = 0x6a COMMA
+    DW_OP_reg27 = 0x6b COMMA
+    DW_OP_reg28 = 0x6c COMMA
+    DW_OP_reg29 = 0x6d COMMA
+    DW_OP_reg30 = 0x6e COMMA
+    DW_OP_reg31 = 0x6f COMMA
+    DW_OP_breg0 = 0x70 COMMA
+    DW_OP_breg1 = 0x71 COMMA
+    DW_OP_breg2 = 0x72 COMMA
+    DW_OP_breg3 = 0x73 COMMA
+    DW_OP_breg4 = 0x74 COMMA
+    DW_OP_breg5 = 0x75 COMMA
+    DW_OP_breg6 = 0x76 COMMA
+    DW_OP_breg7 = 0x77 COMMA
+    DW_OP_breg8 = 0x78 COMMA
+    DW_OP_breg9 = 0x79 COMMA
+    DW_OP_breg10 = 0x7a COMMA
+    DW_OP_breg11 = 0x7b COMMA
+    DW_OP_breg12 = 0x7c COMMA
+    DW_OP_breg13 = 0x7d COMMA
+    DW_OP_breg14 = 0x7e COMMA
+    DW_OP_breg15 = 0x7f COMMA
+    DW_OP_breg16 = 0x80 COMMA
+    DW_OP_breg17 = 0x81 COMMA
+    DW_OP_breg18 = 0x82 COMMA
+    DW_OP_breg19 = 0x83 COMMA
+    DW_OP_breg20 = 0x84 COMMA
+    DW_OP_breg21 = 0x85 COMMA
+    DW_OP_breg22 = 0x86 COMMA
+    DW_OP_breg23 = 0x87 COMMA
+    DW_OP_breg24 = 0x88 COMMA
+    DW_OP_breg25 = 0x89 COMMA
+    DW_OP_breg26 = 0x8a COMMA
+    DW_OP_breg27 = 0x8b COMMA
+    DW_OP_breg28 = 0x8c COMMA
+    DW_OP_breg29 = 0x8d COMMA
+    DW_OP_breg30 = 0x8e COMMA
+    DW_OP_breg31 = 0x8f COMMA
+    DW_OP_regx = 0x90 COMMA
+    DW_OP_fbreg = 0x91 COMMA
+    DW_OP_bregx = 0x92 COMMA
+    DW_OP_piece = 0x93 COMMA
+    DW_OP_deref_size = 0x94 COMMA
+    DW_OP_xderef_size = 0x95 COMMA
+    DW_OP_nop = 0x96 COMMA
+    /* DWARF 3 extensions.  */
+    DW_OP_push_object_address = 0x97 COMMA
+    DW_OP_call2 = 0x98 COMMA
+    DW_OP_call4 = 0x99 COMMA
+    DW_OP_call_ref = 0x9a COMMA
+    /* GNU extensions.	*/
+    DW_OP_GNU_push_tls_address = 0xe0
+IF_NOT_ASM(};)
+
+#define DW_OP_lo_user	0xe0	/* Implementation-defined range start.	*/
+#define DW_OP_hi_user	0xff	/* Implementation-defined range end.  */
+
+/* Type encodings.  */
+ENUM(dwarf_type)
+
+    DW_ATE_void = 0x0 COMMA
+    DW_ATE_address = 0x1 COMMA
+    DW_ATE_boolean = 0x2 COMMA
+    DW_ATE_complex_float = 0x3 COMMA
+    DW_ATE_float = 0x4 COMMA
+    DW_ATE_signed = 0x5 COMMA
+    DW_ATE_signed_char = 0x6 COMMA
+    DW_ATE_unsigned = 0x7 COMMA
+    DW_ATE_unsigned_char = 0x8 COMMA
+    /* DWARF 3.  */
+    DW_ATE_imaginary_float = 0x9
+IF_NOT_ASM(};)
+
+#define	DW_ATE_lo_user 0x80
+#define	DW_ATE_hi_user 0xff
+
+/* Array ordering names and codes.  */
+ENUM(dwarf_array_dim_ordering)
+
+    DW_ORD_row_major = 0 COMMA
+    DW_ORD_col_major = 1
+IF_NOT_ASM(};)
+
+/* Access attribute.  */
+ENUM(dwarf_access_attribute)
+
+    DW_ACCESS_public = 1 COMMA
+    DW_ACCESS_protected = 2 COMMA
+    DW_ACCESS_private = 3
+IF_NOT_ASM(};)
+
+/* Visibility.	*/
+ENUM(dwarf_visibility_attribute)
+
+    DW_VIS_local = 1 COMMA
+    DW_VIS_exported = 2 COMMA
+    DW_VIS_qualified = 3
+IF_NOT_ASM(};)
+
+/* Virtuality.	*/
+ENUM(dwarf_virtuality_attribute)
+
+    DW_VIRTUALITY_none = 0 COMMA
+    DW_VIRTUALITY_virtual = 1 COMMA
+    DW_VIRTUALITY_pure_virtual = 2
+IF_NOT_ASM(};)
+
+/* Case sensitivity.  */
+ENUM(dwarf_id_case)
+
+    DW_ID_case_sensitive = 0 COMMA
+    DW_ID_up_case = 1 COMMA
+    DW_ID_down_case = 2 COMMA
+    DW_ID_case_insensitive = 3
+IF_NOT_ASM(};)
+
+/* Calling convention.	*/
+ENUM(dwarf_calling_convention)
+
+    DW_CC_normal = 0x1 COMMA
+    DW_CC_program = 0x2 COMMA
+    DW_CC_nocall = 0x3
+IF_NOT_ASM(};)
+
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+/* Inline attribute.  */
+ENUM(dwarf_inline_attribute)
+
+    DW_INL_not_inlined = 0 COMMA
+    DW_INL_inlined = 1 COMMA
+    DW_INL_declared_not_inlined = 2 COMMA
+    DW_INL_declared_inlined = 3
+IF_NOT_ASM(};)
+
+/* Discriminant lists.	*/
+ENUM(dwarf_discrim_list)
+
+    DW_DSC_label = 0 COMMA
+    DW_DSC_range = 1
+IF_NOT_ASM(};)
+
+/* Line number opcodes.  */
+ENUM(dwarf_line_number_ops)
+
+    DW_LNS_extended_op = 0 COMMA
+    DW_LNS_copy = 1 COMMA
+    DW_LNS_advance_pc = 2 COMMA
+    DW_LNS_advance_line = 3 COMMA
+    DW_LNS_set_file = 4 COMMA
+    DW_LNS_set_column = 5 COMMA
+    DW_LNS_negate_stmt = 6 COMMA
+    DW_LNS_set_basic_block = 7 COMMA
+    DW_LNS_const_add_pc = 8 COMMA
+    DW_LNS_fixed_advance_pc = 9 COMMA
+    /* DWARF 3.  */
+    DW_LNS_set_prologue_end = 10 COMMA
+    DW_LNS_set_epilogue_begin = 11 COMMA
+    DW_LNS_set_isa = 12
+IF_NOT_ASM(};)
+
+/* Line number extended opcodes.  */
+ENUM(dwarf_line_number_x_ops)
+
+    DW_LNE_end_sequence = 1 COMMA
+    DW_LNE_set_address = 2 COMMA
+    DW_LNE_define_file = 3
+IF_NOT_ASM(};)
+
+/* Call frame information.  */
+ENUM(dwarf_call_frame_info)
+
+    DW_CFA_advance_loc = 0x40 COMMA
+    DW_CFA_offset = 0x80 COMMA
+    DW_CFA_restore = 0xc0 COMMA
+    DW_CFA_nop = 0x00 COMMA
+    DW_CFA_set_loc = 0x01 COMMA
+    DW_CFA_advance_loc1 = 0x02 COMMA
+    DW_CFA_advance_loc2 = 0x03 COMMA
+    DW_CFA_advance_loc4 = 0x04 COMMA
+    DW_CFA_offset_extended = 0x05 COMMA
+    DW_CFA_restore_extended = 0x06 COMMA
+    DW_CFA_undefined = 0x07 COMMA
+    DW_CFA_same_value = 0x08 COMMA
+    DW_CFA_register = 0x09 COMMA
+    DW_CFA_remember_state = 0x0a COMMA
+    DW_CFA_restore_state = 0x0b COMMA
+    DW_CFA_def_cfa = 0x0c COMMA
+    DW_CFA_def_cfa_register = 0x0d COMMA
+    DW_CFA_def_cfa_offset = 0x0e COMMA
+
+    /* DWARF 3.  */
+    DW_CFA_def_cfa_expression = 0x0f COMMA
+    DW_CFA_expression = 0x10 COMMA
+    DW_CFA_offset_extended_sf = 0x11 COMMA
+    DW_CFA_def_cfa_sf = 0x12 COMMA
+    DW_CFA_def_cfa_offset_sf = 0x13 COMMA
+
+    /* SGI/MIPS specific.  */
+    DW_CFA_MIPS_advance_loc8 = 0x1d COMMA
+
+    /* GNU extensions.	*/
+    DW_CFA_GNU_window_save = 0x2d COMMA
+    DW_CFA_GNU_args_size = 0x2e COMMA
+    DW_CFA_GNU_negative_offset_extended = 0x2f
+IF_NOT_ASM(};)
+
+#define DW_CIE_ID	  0xffffffff
+#define DW_CIE_VERSION	  1
+
+#define DW_CFA_extended   0
+#define DW_CFA_lo_user	  0x1c
+#define DW_CFA_hi_user	  0x3f
+
+#define DW_CHILDREN_no		     0x00
+#define DW_CHILDREN_yes		     0x01
+
+#define DW_ADDR_none		0
+
+/* Source language names and codes.  */
+ENUM(dwarf_source_language)
+
+    DW_LANG_C89 = 0x0001 COMMA
+    DW_LANG_C = 0x0002 COMMA
+    DW_LANG_Ada83 = 0x0003 COMMA
+    DW_LANG_C_plus_plus = 0x0004 COMMA
+    DW_LANG_Cobol74 = 0x0005 COMMA
+    DW_LANG_Cobol85 = 0x0006 COMMA
+    DW_LANG_Fortran77 = 0x0007 COMMA
+    DW_LANG_Fortran90 = 0x0008 COMMA
+    DW_LANG_Pascal83 = 0x0009 COMMA
+    DW_LANG_Modula2 = 0x000a COMMA
+    DW_LANG_Java = 0x000b COMMA
+    /* DWARF 3.  */
+    DW_LANG_C99 = 0x000c COMMA
+    DW_LANG_Ada95 = 0x000d COMMA
+    DW_LANG_Fortran95 = 0x000e COMMA
+    /* MIPS.  */
+    DW_LANG_Mips_Assembler = 0x8001 COMMA
+    /* UPC.  */
+    DW_LANG_Upc = 0x8765
+IF_NOT_ASM(};)
+
+#define DW_LANG_lo_user 0x8000	/* Implementation-defined range start.	*/
+#define DW_LANG_hi_user 0xffff	/* Implementation-defined range start.	*/
+
+/* Names and codes for macro information.  */
+ENUM(dwarf_macinfo_record_type)
+
+    DW_MACINFO_define = 1 COMMA
+    DW_MACINFO_undef = 2 COMMA
+    DW_MACINFO_start_file = 3 COMMA
+    DW_MACINFO_end_file = 4 COMMA
+    DW_MACINFO_vendor_ext = 255
+IF_NOT_ASM(};)
+
+/* @@@ For use with GNU frame unwind information.  */
+
+#define DW_EH_PE_absptr		0x00
+#define DW_EH_PE_omit		0xff
+
+#define DW_EH_PE_uleb128	0x01
+#define DW_EH_PE_udata2		0x02
+#define DW_EH_PE_udata4		0x03
+#define DW_EH_PE_udata8		0x04
+#define DW_EH_PE_sleb128	0x09
+#define DW_EH_PE_sdata2		0x0A
+#define DW_EH_PE_sdata4		0x0B
+#define DW_EH_PE_sdata8		0x0C
+#define DW_EH_PE_signed		0x08
+
+#define DW_EH_PE_pcrel		0x10
+#define DW_EH_PE_textrel	0x20
+#define DW_EH_PE_datarel	0x30
+#define DW_EH_PE_funcrel	0x40
+#define DW_EH_PE_aligned	0x50
+
+#define DW_EH_PE_indirect	0x80
+
+#endif /* _ELF_DWARF2_H */
--- diff/include/linux/hpet.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/hpet.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,131 @@
+#ifndef	__HPET__
+#define	__HPET__ 1
+
+/*
+ * Offsets into HPET Registers
+ */
+
+struct hpet {
+	u64 hpet_cap;		/* capabilities */
+	u64 res0;		/* reserved */
+	u64 hpet_config;	/* configuration */
+	u64 res1;		/* reserved */
+	u64 hpet_isr;		/* interrupt status reg */
+	u64 res2[25];		/* reserved */
+	union {			/* main counter */
+		u64 _hpet_mc64;
+		u32 _hpet_mc32;
+		unsigned long _hpet_mc;
+	} _u0;
+	u64 res3;		/* reserved */
+	struct hpet_timer {
+		u64 hpet_config;	/* configuration/cap */
+		union {		/* timer compare register */
+			u64 _hpet_hc64;
+			u32 _hpet_hc32;
+			unsigned long _hpet_compare;
+		} _u1;
+		u64 hpet_fsb[2];	/* FSB route */
+	} hpet_timers[1];
+};
+
+#define	hpet_mc		_u0._hpet_mc
+#define	hpet_compare	_u1._hpet_compare
+
+#define	HPET_MAX_TIMERS	(32)
+
+/*
+ * HPET general capabilities register
+ */
+
+#define	HPET_COUNTER_CLK_PERIOD_MASK	(0xffffffff00000000ULL)
+#define	HPET_COUNTER_CLK_PERIOD_SHIFT	(32UL)
+#define	HPET_VENDOR_ID_MASK		(0x00000000ffff0000ULL)
+#define	HPET_VENDOR_ID_SHIFT		(16ULL)
+#define	HPET_LEG_RT_CAP_MASK		(0x8000)
+#define	HPET_COUNTER_SIZE_MASK		(0x2000)
+#define	HPET_NUM_TIM_CAP_MASK		(0x1f00)
+#define	HPET_NUM_TIM_CAP_SHIFT		(8ULL)
+
+/*
+ * HPET general configuration register
+ */
+
+#define	HPET_LEG_RT_CNF_MASK		(2UL)
+#define	HPET_ENABLE_CNF_MASK		(1UL)
+
+/*
+ * HPET interrupt status register
+ */
+
+#define	HPET_ISR_CLEAR(HPET, TIMER)				\
+		(HPET)->hpet_isr |= (1UL << TIMER)
+
+/*
+ * Timer configuration register
+ */
+
+#define	Tn_INT_ROUTE_CAP_MASK		(0xffffffff00000000ULL)
+#define	Tn_INI_ROUTE_CAP_SHIFT		(32UL)
+#define	Tn_FSB_INT_DELCAP_MASK		(0x8000UL)
+#define	Tn_FSB_INT_DELCAP_SHIFT		(15)
+#define	Tn_FSB_EN_CNF_MASK		(0x4000UL)
+#define	Tn_FSB_EN_CNF_SHIFT		(14)
+#define	Tn_INT_ROUTE_CNF_MASK		(0x3e00UL)
+#define	Tn_INT_ROUTE_CNF_SHIFT		(9)
+#define	Tn_32MODE_CNF_MASK		(0x0100UL)
+#define	Tn_VAL_SET_CNF_MASK		(0x0040UL)
+#define	Tn_SIZE_CAP_MASK		(0x0020UL)
+#define	Tn_PER_INT_CAP_MASK		(0x0010UL)
+#define	Tn_TYPE_CNF_MASK		(0x0008UL)
+#define	Tn_INT_ENB_CNF_MASK		(0x0004UL)
+#define	Tn_INT_TYPE_CNF_MASK		(0x0002UL)
+
+/*
+ * Timer FSB Interrupt Route Register
+ */
+
+#define	Tn_FSB_INT_ADDR_MASK		(0xffffffff00000000ULL)
+#define	Tn_FSB_INT_ADDR_SHIFT		(32UL)
+#define	Tn_FSB_INT_VAL_MASK		(0x00000000ffffffffULL)
+
+struct hpet_info {
+	unsigned long hi_ireqfreq;	/* Hz */
+	unsigned long hi_flags;	/* information */
+};
+
+#define	HPET_INFO_PERIODIC	0x0001	/* timer is periodic */
+
+#define	HPET_IE_ON	_IO('h', 0x01)	/* interrupt on */
+#define	HPET_IE_OFF	_IO('h', 0x02)	/* interrupt off */
+#define	HPET_INFO	_IOR('h', 0x03, struct hpet_info)
+#define	HPET_EPI	_IO('h', 0x04)	/* enable periodic */
+#define	HPET_DPI	_IO('h', 0x05)	/* disable periodic */
+#define	HPET_IRQFREQ	_IOW('h', 0x6, unsigned long)	/* IRQFREQ usec */
+
+/*
+ * exported interfaces
+ */
+
+struct hpet_task {
+	void (*ht_func) (void *);
+	void *ht_data;
+	void *ht_opaque;
+};
+
+struct hpet_data {
+	unsigned long hd_address;
+	unsigned short hd_nirqs;
+	unsigned short hd_flags;
+	unsigned int hd_state;	/* timer allocated */
+	unsigned int hd_irq[HPET_MAX_TIMERS];
+};
+
+#define	HPET_DATA_PLATFORM	0x0001	/* platform call to hpet_alloc */
+
+int hpet_alloc(struct hpet_data *);
+int hpet_register(struct hpet_task *, int);
+int hpet_unregister(struct hpet_task *);
+int hpet_control(struct hpet_task *, unsigned int, unsigned long);
+
+#endif				/* !__HPET__ */
--- diff/include/linux/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/lockmeter.h	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,320 @@
+/*
+ *  Copyright (C) 1999-2002 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com) Feb-Apr 2000
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code to include/asm/lockmeter.h.
+ *
+ */
+
+#ifndef _LINUX_LOCKMETER_H
+#define _LINUX_LOCKMETER_H
+
+
+/*---------------------------------------------------
+ *	architecture-independent lockmeter.h
+ *-------------------------------------------------*/
+
+/*
+ * raybry -- version 2: added efficient hold time statistics
+ *           requires lstat recompile, so flagged as new version
+ * raybry -- version 3: added global reader lock data
+ * hawkes -- version 4: removed some unnecessary fields to simplify mips64 port
+ */
+#define LSTAT_VERSION	5
+
+int	lstat_update(void*, void*, int);
+int	lstat_update_time(void*, void*, int, uint32_t);
+
+/*
+ * Currently, the mips64 and sparc64 kernels talk to a 32-bit lockstat, so we
+ * need to force compatibility in the inter-communication data structure.
+ */
+
+#if defined(CONFIG_MIPS32_COMPAT)
+#define TIME_T		uint32_t
+#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64)
+#define TIME_T		uint64_t
+#else
+#define TIME_T		time_t
+#endif
+
+#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32)
+#define POINTER		void *
+#else
+#define	POINTER		int64_t
+#endif
+
+/*
+ * Values for the "action" parameter passed to lstat_update.
+ *	ZZZ - do we want a try-success status here???
+ */
+#define LSTAT_ACT_NO_WAIT	0
+#define LSTAT_ACT_SPIN		1
+#define LSTAT_ACT_REJECT	2
+#define LSTAT_ACT_WW_SPIN       3
+#define LSTAT_ACT_SLEPT		4 /* UNUSED */
+
+#define LSTAT_ACT_MAX_VALUES	4 /* NOTE: Increase to 5 if use ACT_SLEPT */
+
+/*
+ * Special values for the low 2 bits of an RA passed to
+ * lstat_update.
+ */
+/* we use these values to figure out what kind of lock data */
+/* is stored in the statistics table entry at index ....... */
+#define LSTAT_RA_SPIN           0  /* spin lock data */
+#define LSTAT_RA_READ           1  /* read lock statistics */
+#define LSTAT_RA_SEMA		2  /* RESERVED */
+#define LSTAT_RA_WRITE          3  /* write lock statistics*/
+
+#define LSTAT_RA(n)	\
+	((void*)( ((unsigned long)__builtin_return_address(0) & ~3) | n) )
+
+/*
+ * Constants used for lock addresses in the lstat_directory
+ * to indicate special values of the lock address.
+ */
+#define	LSTAT_MULTI_LOCK_ADDRESS	NULL
+
+/*
+ * Maximum size of the lockstats tables. Increase this value
+ * if its not big enough. (Nothing bad happens if its not
+ * big enough although some locks will not be monitored.)
+ * We record overflows of this quantity in lstat_control.dir_overflows
+ *
+ * Note:  The max value here must fit into the field set
+ * and obtained by the macro's PUT_INDEX() and GET_INDEX().
+ * This value depends on how many bits are available in the
+ * lock word in the particular machine implementation we are on.
+ */
+#define LSTAT_MAX_STAT_INDEX		2000
+
+/*
+ * Size and mask for the hash table into the directory.
+ */
+#define LSTAT_HASH_TABLE_SIZE		4096		/* must be 2**N */
+#define LSTAT_HASH_TABLE_MASK		(LSTAT_HASH_TABLE_SIZE-1)
+
+#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
+
+/*
+ *	This defines an entry in the lockstat directory. It contains
+ *	information about a lock being monitored.
+ *	A directory entry only contains the lock identification -
+ *	counts on usage of the lock are kept elsewhere in a per-cpu
+ *	data structure to minimize cache line pinging.
+ */
+typedef struct {
+	POINTER	caller_ra;		  /* RA of code that set lock */
+	POINTER	lock_ptr;		  /* lock address */
+	ushort	next_stat_index;  /* Used to link multiple locks that have the same hash table value */
+} lstat_directory_entry_t;
+
+/*
+ *	A multi-dimensioned array used to contain counts for lock accesses.
+ *	The array is 3-dimensional:
+ *		- CPU number. Keep from thrashing cache lines between CPUs
+ *		- Directory entry index. Identifies the lock
+ *		- Action. Indicates what kind of contention occurred on an
+ *		  access to the lock.
+ *
+ *	The index of an entry in the directory is the same as the 2nd index
+ *	of the entry in the counts array.
+ */
+/*
+ *  This table contains data for spin_locks, write locks, and read locks
+ *  Not all data is used for all cases.  In particular, the hold time
+ *  information is not stored here for read locks since that is a global
+ *  (e. g. cannot be separated out by return address) quantity.
+ *  See the lstat_read_lock_counts_t structure for the global read lock
+ *  hold time.
+ */
+typedef struct {
+	uint64_t    cum_wait_ticks;	/* sum of wait times               */
+	                                /* for write locks, sum of time a  */
+					/* writer is waiting for a reader  */
+	int64_t	    cum_hold_ticks;	/* cumulative sum of holds         */
+	                                /* not used for read mode locks    */
+					/* must be signed. ............... */
+	uint32_t    max_wait_ticks;	/* max waiting time                */
+	uint32_t    max_hold_ticks;	/* max holding time                */
+	uint64_t    cum_wait_ww_ticks;  /* sum times writer waits on writer*/
+	uint32_t    max_wait_ww_ticks;  /* max wait time writer vs writer  */
+	                                /* prev 2 only used for write locks*/
+	uint32_t    acquire_time;       /* time lock acquired this CPU     */
+	uint32_t    count[LSTAT_ACT_MAX_VALUES];
+} lstat_lock_counts_t;
+
+typedef lstat_lock_counts_t	lstat_cpu_counts_t[LSTAT_MAX_STAT_INDEX];
+
+/*
+ * User request to:
+ *	- turn statistic collection on/off, or to reset
+ */
+#define LSTAT_OFF	 0
+#define LSTAT_ON	 1
+#define LSTAT_RESET      2
+#define LSTAT_RELEASE    3
+
+#define LSTAT_MAX_READ_LOCK_INDEX 1000
+typedef struct {
+	POINTER	    lock_ptr;            /* address of lock for output stats */
+	uint32_t    read_lock_count;
+	int64_t     cum_hold_ticks;       /* sum of read lock hold times over */
+	                                  /* all callers. ....................*/
+	uint32_t    write_index;          /* last write lock hash table index */
+	uint32_t    busy_periods;         /* count of busy periods ended this */
+	uint64_t    start_busy;           /* time this busy period started. ..*/
+	uint64_t    busy_ticks;           /* sum of busy periods this lock. ..*/
+	uint64_t    max_busy;             /* longest busy period for this lock*/
+	uint32_t    max_readers;          /* maximum number of readers ...... */
+#ifdef USER_MODE_TESTING
+	rwlock_t    entry_lock;           /* lock for this read lock entry... */
+	                                  /* avoid having more than one rdr at*/
+	                                  /* needed for user space testing... */
+	                                  /* not needed for kernel 'cause it  */
+					  /* is non-preemptive. ............. */
+#endif
+} lstat_read_lock_counts_t;
+typedef lstat_read_lock_counts_t	lstat_read_lock_cpu_counts_t[LSTAT_MAX_READ_LOCK_INDEX];
+
+#if defined(__KERNEL__) || defined(USER_MODE_TESTING)
+
+#ifndef USER_MODE_TESTING
+#include <asm/lockmeter.h>
+#else
+#include "asm_newlockmeter.h"
+#endif
+
+/*
+ * Size and mask for the hash table into the directory.
+ */
+#define LSTAT_HASH_TABLE_SIZE		4096		/* must be 2**N */
+#define LSTAT_HASH_TABLE_MASK		(LSTAT_HASH_TABLE_SIZE-1)
+
+#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
+
+/*
+ * This version eliminates the per processor lock stack.  What we do is to
+ * store the index of the lock hash structure in unused bits in the lock
+ * itself.  Then on unlock we can find the statistics record without doing
+ * any additional hash or lock stack lookup.  This works for spin_locks.
+ * Hold time reporting is now basically as cheap as wait time reporting
+ * so we ignore the difference between LSTAT_ON_HOLD and LSTAT_ON_WAIT
+ * as in version 1.1.* of lockmeter.
+ *
+ * For rw_locks, we store the index of a global reader stats structure in
+ * the lock and the writer index is stored in the latter structure.
+ * For read mode locks we hash at the time of the lock to find an entry
+ * in the directory for reader wait time and the like.
+ * At unlock time for read mode locks, we update just the global structure
+ * so we don't need to know the reader directory index value at unlock time.
+ *
+ */
+
+/*
+ * Protocol to change lstat_control.state
+ *   This is complicated because we don't want the cum_hold_time for
+ * a rw_lock to be decremented in _read_lock_ without making sure it
+ * is incremented in _read_lock_ and vice versa.  So here is the
+ * way we change the state of lstat_control.state:
+ * I.  To Turn Statistics On
+ *     After allocating storage, set lstat_control.state non-zero.
+ * This works because we don't start updating statistics for in use
+ * locks until the reader lock count goes to zero.
+ * II. To Turn Statistics Off:
+ * (0)  Disable interrupts on this CPU
+ * (1)  Seize the lstat_control.directory_lock
+ * (2)  Obtain the current value of lstat_control.next_free_read_lock_index
+ * (3)  Store a zero in lstat_control.state.
+ * (4)  Release the lstat_control.directory_lock
+ * (5)  For each lock in the read lock list up to the saved value
+ *      (well, -1) of the next_free_read_lock_index, do the following:
+ *      (a)  Check validity of the stored lock address
+ *           by making sure that the word at the saved addr
+ *           has an index that matches this entry.  If not
+ *           valid, then skip this entry.
+ *      (b)  If there is a write lock already set on this lock,
+ *           skip to (d) below.
+ *      (c)  Set a non-metered write lock on the lock
+ *      (d)  set the cached INDEX in the lock to zero
+ *      (e)  Release the non-metered write lock.
+ * (6)  Re-enable interrupts
+ *
+ * These rules ensure that a read lock will not have its statistics
+ * partially updated even though the global lock recording state has
+ * changed.  See put_lockmeter_info() for implementation.
+ *
+ * The reason for (b) is that there may be write locks set on the
+ * syscall path to put_lockmeter_info() from user space.  If we do
+ * not do this check, then we can deadlock.  A similar problem would
+ * occur if the lock was read locked by the current CPU.  At the
+ * moment this does not appear to happen.
+ */
+
+/*
+ * Main control structure for lockstat. Used to turn statistics on/off
+ * and to maintain directory info.
+ */
+typedef struct {
+	int				state;
+	spinlock_t		control_lock;		/* used to serialize turning statistics on/off   */
+	spinlock_t		directory_lock;		/* for serialize adding entries to directory     */
+	volatile int	next_free_dir_index;/* next free entry in the directory */
+	/* FIXME not all of these fields are used / needed .............. */
+                /* the following fields represent data since     */
+		/* first "lstat on" or most recent "lstat reset" */
+	TIME_T      first_started_time;     /* time when measurement first enabled */
+	TIME_T      started_time;           /* time when measurement last started  */
+	TIME_T      ending_time;            /* time when measurement last disabled */
+	uint64_t    started_cycles64;       /* cycles when measurement last started          */
+	uint64_t    ending_cycles64;        /* cycles when measurement last disabled         */
+	uint64_t    enabled_cycles64;       /* total cycles with measurement enabled         */
+	int         intervals;              /* number of measurement intervals recorded      */
+	                                    /* i. e. number of times did lstat on;lstat off  */
+	lstat_directory_entry_t	*dir;		/* directory */
+	int         dir_overflow;           /* count of times ran out of space in directory  */
+	int         rwlock_overflow;        /* count of times we couldn't allocate a rw block*/
+	ushort		*hashtab;		 	    /* hash table for quick dir scans */
+	lstat_cpu_counts_t	*counts[NR_CPUS];	 /* Array of pointers to per-cpu stats */
+    int         next_free_read_lock_index;   /* next rwlock reader (global) stats block  */
+    lstat_read_lock_cpu_counts_t *read_lock_counts[NR_CPUS]; /* per cpu read lock stats  */
+} lstat_control_t;
+
+#endif	/* defined(__KERNEL__) || defined(USER_MODE_TESTING) */
+
+typedef struct {
+	short		lstat_version;		/* version of the data */
+	short		state;			/* the current state is returned */
+	int		maxcpus;		/* Number of cpus present */
+	int		next_free_dir_index;	/* index of the next free directory entry */
+	TIME_T          first_started_time;	/* when measurement enabled for first time */
+	TIME_T          started_time;		/* time in secs since 1969 when stats last turned on  */
+	TIME_T		ending_time;		/* time in secs since 1969 when stats last turned off */
+	uint32_t	cycleval;		/* cycles per second */
+#ifdef notyet
+	void		*kernel_magic_addr;	/* address of kernel_magic */
+	void		*kernel_end_addr;	/* contents of kernel magic (points to "end") */
+#endif
+	int              next_free_read_lock_index; /* index of next (global) read lock stats struct */
+	uint64_t         started_cycles64;	/* cycles when measurement last started        */
+	uint64_t         ending_cycles64;	/* cycles when stats last turned off           */
+	uint64_t         enabled_cycles64;	/* total cycles with measurement enabled       */
+	int              intervals;		/* number of measurement intervals recorded      */
+						/* i.e. number of times we did lstat on;lstat off*/
+	int              dir_overflow;		/* number of times we wanted more space in directory */
+	int              rwlock_overflow;	/* # of times we wanted more space in read_locks_count */
+	struct new_utsname   uts;		/* info about machine where stats are measured */
+						/* -T option of lockstat allows data to be     */
+						/* moved to another machine. ................. */
+} lstat_user_request_t;
+
+#endif /* _LINUX_LOCKMETER_H */
--- diff/kernel/lockmeter.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/lockmeter.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,1178 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.c by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+#include <linux/utsname.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/lockmeter.h>
+
+#define ASSERT(cond)
+#define bzero(loc,size)		memset(loc,0,size)
+
+/*<---------------------------------------------------*/
+/*              lockmeter.c                           */
+/*>---------------------------------------------------*/
+
+static lstat_control_t lstat_control __cacheline_aligned =
+	{ LSTAT_OFF, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
+	  19 * 0, NR_CPUS * 0, 0, NR_CPUS * 0 };
+
+static ushort lstat_make_dir_entry(void *, void *);
+
+/*
+ * lstat_lookup
+ *
+ * Given a RA, locate the directory entry for the lock.
+ */
+static ushort
+lstat_lookup(void *lock_ptr, void *caller_ra)
+{
+	ushort index;
+	lstat_directory_entry_t *dirp;
+
+	dirp = lstat_control.dir;
+
+	index = lstat_control.hashtab[DIRHASH(caller_ra)];
+	while (dirp[index].caller_ra != caller_ra) {
+		if (index == 0) {
+			return lstat_make_dir_entry(lock_ptr, caller_ra);
+		}
+		index = dirp[index].next_stat_index;
+	}
+
+	if (dirp[index].lock_ptr != NULL && dirp[index].lock_ptr != lock_ptr) {
+		dirp[index].lock_ptr = NULL;
+	}
+
+	return index;
+}
+
+/*
+ * lstat_make_dir_entry
+ * Called to add a new lock to the lock directory.
+ */
+static ushort
+lstat_make_dir_entry(void *lock_ptr, void *caller_ra)
+{
+	lstat_directory_entry_t *dirp;
+	ushort index, hindex;
+	unsigned long flags;
+
+	/* lock the table without recursively reentering this metering code */
+	local_irq_save(flags);
+	_raw_spin_lock(&lstat_control.directory_lock);
+
+	hindex = DIRHASH(caller_ra);
+	index = lstat_control.hashtab[hindex];
+	dirp = lstat_control.dir;
+	while (index && dirp[index].caller_ra != caller_ra)
+		index = dirp[index].next_stat_index;
+
+	if (index == 0) {
+		if (lstat_control.next_free_dir_index < LSTAT_MAX_STAT_INDEX) {
+			index = lstat_control.next_free_dir_index++;
+			lstat_control.dir[index].caller_ra = caller_ra;
+			lstat_control.dir[index].lock_ptr = lock_ptr;
+			lstat_control.dir[index].next_stat_index =
+				lstat_control.hashtab[hindex];
+			lstat_control.hashtab[hindex] = index;
+		} else {
+			lstat_control.dir_overflow++;
+		}
+	}
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+	return index;
+}
+
+int
+lstat_update(void *lock_ptr, void *caller_ra, int action)
+{
+	int index;
+	int cpu;
+
+	ASSERT(action < LSTAT_ACT_MAX_VALUES);
+
+	if (lstat_control.state == LSTAT_OFF)
+		return 0;
+
+	index = lstat_lookup(lock_ptr, caller_ra);
+	cpu = THIS_CPU_NUMBER;
+	(*lstat_control.counts[cpu])[index].count[action]++;
+	(*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
+
+	return index;
+}
+
+int
+lstat_update_time(void *lock_ptr, void *caller_ra, int action, uint32_t ticks)
+{
+	ushort index;
+	int cpu;
+
+	ASSERT(action < LSTAT_ACT_MAX_VALUES);
+
+	if (lstat_control.state == LSTAT_OFF)
+		return 0;
+
+	index = lstat_lookup(lock_ptr, caller_ra);
+	cpu = THIS_CPU_NUMBER;
+	(*lstat_control.counts[cpu])[index].count[action]++;
+	(*lstat_control.counts[cpu])[index].cum_wait_ticks += (uint64_t) ticks;
+	if ((*lstat_control.counts[cpu])[index].max_wait_ticks < ticks)
+		(*lstat_control.counts[cpu])[index].max_wait_ticks = ticks;
+
+	(*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
+
+	return index;
+}
+
+void
+_metered_spin_lock(spinlock_t * lock_ptr)
+{
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_spin_lock(lock_ptr);	/* do the real lock */
+		PUT_INDEX(lock_ptr, 0);	/* clean index in case lockmetering  */
+		/* gets turned on before unlock */
+	} else {
+		void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
+		int index;
+
+		if (_raw_spin_trylock(lock_ptr)) {
+			index = lstat_update(lock_ptr, this_pc,
+						LSTAT_ACT_NO_WAIT);
+		} else {
+			uint32_t start_cycles = get_cycles();
+			_raw_spin_lock(lock_ptr);	/* do the real lock */
+			index = lstat_update_time(lock_ptr, this_pc,
+				LSTAT_ACT_SPIN, get_cycles() - start_cycles);
+		}
+		/* save the index in the lock itself for use in spin unlock */
+		PUT_INDEX(lock_ptr, index);
+	}
+}
+
+int
+_metered_spin_trylock(spinlock_t * lock_ptr)
+{
+	if (lstat_control.state == LSTAT_OFF) {
+		return _raw_spin_trylock(lock_ptr);
+	} else {
+		int retval;
+		void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
+
+		if ((retval = _raw_spin_trylock(lock_ptr))) {
+			int index = lstat_update(lock_ptr, this_pc,
+						LSTAT_ACT_NO_WAIT);
+			/*
+			 * save the index in the lock itself for use in spin
+			 * unlock
+			 */
+			PUT_INDEX(lock_ptr, index);
+		} else {
+			lstat_update(lock_ptr, this_pc, LSTAT_ACT_REJECT);
+		}
+
+		return retval;
+	}
+}
+
+void
+_metered_spin_unlock(spinlock_t * lock_ptr)
+{
+	int index = -1;
+
+	if (lstat_control.state != LSTAT_OFF) {
+		index = GET_INDEX(lock_ptr);
+		/*
+		 * If statistics were turned off when we set the lock,
+		 * then the index can be zero.  If that is the case,
+		 * then collect no stats on this call.
+		 */
+		if (index > 0) {
+			uint32_t hold_time;
+			int cpu = THIS_CPU_NUMBER;
+			hold_time = get_cycles() -
+			 (*lstat_control.counts[cpu])[index].acquire_time;
+			(*lstat_control.counts[cpu])[index].cum_hold_ticks +=
+				(uint64_t) hold_time;
+			if ((*lstat_control.counts[cpu])[index].max_hold_ticks <
+			    hold_time)
+				(*lstat_control.counts[cpu])[index].
+				    max_hold_ticks = hold_time;
+		}
+	}
+
+	/* make sure we don't have a stale index value saved */
+	PUT_INDEX(lock_ptr, 0);
+	_raw_spin_unlock(lock_ptr);	/* do the real unlock */
+}
+
+/*
+ * allocate the next global read lock structure and store its index
+ * in the rwlock at "lock_ptr".
+ */
+uint32_t
+alloc_rwlock_struct(rwlock_t * rwlock_ptr)
+{
+	int index;
+	unsigned long flags;
+	int cpu = THIS_CPU_NUMBER;
+
+	/* If we've already overflowed, then do a quick exit */
+	if (lstat_control.next_free_read_lock_index >
+			LSTAT_MAX_READ_LOCK_INDEX) {
+		lstat_control.rwlock_overflow++;
+		return 0;
+	}
+
+	local_irq_save(flags);
+	_raw_spin_lock(&lstat_control.directory_lock);
+
+	/* It is possible this changed while we were waiting for the directory_lock */
+	if (lstat_control.state == LSTAT_OFF) {
+		index = 0;
+		goto unlock;
+	}
+
+	/* It is possible someone else got here first and set the index */
+	if ((index = GET_RWINDEX(rwlock_ptr)) == 0) {
+		/*
+		 * we can't turn on read stats for this lock while there are
+		 * readers (this would mess up the running hold time sum at
+		 * unlock time)
+		 */
+		if (RWLOCK_READERS(rwlock_ptr) != 0) {
+			index = 0;
+			goto unlock;
+		}
+
+		/*
+		 * if stats are turned on after being off, we may need to
+		 * return an old index from when the statistics were on last
+		 * time.
+		 */
+		for (index = 1; index < lstat_control.next_free_read_lock_index;
+				index++)
+			if ((*lstat_control.read_lock_counts[cpu])[index].
+					lock_ptr == rwlock_ptr)
+				goto put_index_and_unlock;
+
+		/* allocate the next global read lock structure */
+		if (lstat_control.next_free_read_lock_index >=
+		    LSTAT_MAX_READ_LOCK_INDEX) {
+			lstat_control.rwlock_overflow++;
+			index = 0;
+			goto unlock;
+		}
+		index = lstat_control.next_free_read_lock_index++;
+
+		/*
+		 * initialize the global read stats data structure for each
+		 * cpu
+		 */
+		for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+			(*lstat_control.read_lock_counts[cpu])[index].lock_ptr =
+				rwlock_ptr;
+		}
+put_index_and_unlock:
+		/* store the index for the read lock structure into the lock */
+		PUT_RWINDEX(rwlock_ptr, index);
+	}
+
+unlock:
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+	return index;
+}
+
+void
+_metered_read_lock(rwlock_t * rwlock_ptr)
+{
+	void *this_pc;
+	uint32_t start_cycles;
+	int index;
+	int cpu;
+	unsigned long flags;
+	int readers_before, readers_after;
+	uint64_t cycles64;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_read_lock(rwlock_ptr);
+		/* clean index in case lockmetering turns on before an unlock */
+		PUT_RWINDEX(rwlock_ptr, 0);
+		return;
+	}
+
+	this_pc = LSTAT_RA(LSTAT_RA_READ);
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* allocate the global stats entry for this lock, if needed */
+	if (index == 0)
+		index = alloc_rwlock_struct(rwlock_ptr);
+
+	readers_before = RWLOCK_READERS(rwlock_ptr);
+	if (_raw_read_trylock(rwlock_ptr)) {
+		/*
+		 * We have decremented the lock to count a new reader,
+		 * and have confirmed that no writer has it locked.
+		 */
+		/* update statistics if enabled */
+		if (index > 0) {
+			local_irq_save(flags);
+			lstat_update((void *) rwlock_ptr, this_pc,
+					LSTAT_ACT_NO_WAIT);
+			/* preserve value of TSC so cum_hold_ticks and start_busy use same value */
+			cycles64 = get_cycles64();
+			(*lstat_control.read_lock_counts[cpu])[index].
+				cum_hold_ticks -= cycles64;
+
+			/* record time and cpu of start of busy period */
+			/* this is not perfect (some race conditions are possible) */
+			if (readers_before == 0) {
+				(*lstat_control.read_lock_counts[cpu])[index].
+					start_busy = cycles64;
+				PUT_RW_CPU(rwlock_ptr, cpu);
+			}
+			readers_after = RWLOCK_READERS(rwlock_ptr);
+			if (readers_after >
+				(*lstat_control.read_lock_counts[cpu])[index].
+					max_readers)
+				(*lstat_control.read_lock_counts[cpu])[index].
+					max_readers = readers_after;
+			local_irq_restore(flags);
+		}
+
+		return;
+	}
+	/* If we get here, then we could not quickly grab the read lock */
+
+	start_cycles = get_cycles();	/* start counting the wait time */
+
+	/* Now spin until read_lock is successful */
+	_raw_read_lock(rwlock_ptr);
+
+	lstat_update_time((void *) rwlock_ptr, this_pc, LSTAT_ACT_SPIN,
+			  get_cycles() - start_cycles);
+
+	/* update statistics if they are enabled for this lock */
+	if (index > 0) {
+		local_irq_save(flags);
+		cycles64 = get_cycles64();
+		(*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks -=
+				cycles64;
+
+		/* this is not perfect (some race conditions are possible) */
+		if (readers_before == 0) {
+			(*lstat_control.read_lock_counts[cpu])[index].
+				start_busy = cycles64;
+			PUT_RW_CPU(rwlock_ptr, cpu);
+		}
+		readers_after = RWLOCK_READERS(rwlock_ptr);
+		if (readers_after >
+		    (*lstat_control.read_lock_counts[cpu])[index].max_readers)
+			(*lstat_control.read_lock_counts[cpu])[index].
+				max_readers = readers_after;
+		local_irq_restore(flags);
+	}
+}
+
+void
+_metered_read_unlock(rwlock_t * rwlock_ptr)
+{
+	int index;
+	int cpu;
+	unsigned long flags;
+	uint64_t busy_length;
+	uint64_t cycles64;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_read_unlock(rwlock_ptr);
+		return;
+	}
+
+	index = GET_RWINDEX(rwlock_ptr);
+	cpu = THIS_CPU_NUMBER;
+
+	if (index > 0) {
+		local_irq_save(flags);
+		/*
+		 * preserve value of TSC so cum_hold_ticks and busy_ticks are
+		 * consistent.
+		 */
+		cycles64 = get_cycles64();
+		(*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks +=
+			cycles64;
+		(*lstat_control.read_lock_counts[cpu])[index].read_lock_count++;
+
+		/*
+		 * once again, this is not perfect (some race conditions are
+		 * possible)
+		 */
+		if (RWLOCK_READERS(rwlock_ptr) == 1) {
+			int cpu1 = GET_RW_CPU(rwlock_ptr);
+			uint64_t last_start_busy =
+				(*lstat_control.read_lock_counts[cpu1])[index].
+					start_busy;
+			(*lstat_control.read_lock_counts[cpu])[index].
+				busy_periods++;
+			if (cycles64 > last_start_busy) {
+				busy_length = cycles64 - last_start_busy;
+				(*lstat_control.read_lock_counts[cpu])[index].
+					busy_ticks += busy_length;
+				if (busy_length >
+					(*lstat_control.
+						read_lock_counts[cpu])[index].
+							max_busy)
+					(*lstat_control.
+					 read_lock_counts[cpu])[index].
+						max_busy = busy_length;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	_raw_read_unlock(rwlock_ptr);
+}
+
+void
+_metered_write_lock(rwlock_t * rwlock_ptr)
+{
+	uint32_t start_cycles;
+	void *this_pc;
+	uint32_t spin_ticks = 0; /* in anticipation of a potential wait */
+	int index;
+	int write_index = 0;
+	int cpu;
+	enum {
+		writer_writer_conflict,
+		writer_reader_conflict
+	} why_wait = writer_writer_conflict;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_write_lock(rwlock_ptr);
+		/* clean index in case lockmetering turns on before an unlock */
+		PUT_RWINDEX(rwlock_ptr, 0);
+		return;
+	}
+
+	this_pc = LSTAT_RA(LSTAT_RA_WRITE);
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* allocate the global stats entry for this lock, if needed */
+	if (index == 0) {
+		index = alloc_rwlock_struct(rwlock_ptr);
+	}
+
+	if (_raw_write_trylock(rwlock_ptr)) {
+		/* We acquired the lock on the first try */
+		write_index = lstat_update((void *) rwlock_ptr, this_pc,
+					LSTAT_ACT_NO_WAIT);
+		/* save the write_index for use in unlock if stats enabled */
+		if (index > 0)
+			(*lstat_control.read_lock_counts[cpu])[index].
+				write_index = write_index;
+		return;
+	}
+
+	/* If we get here, then we could not quickly grab the write lock */
+	start_cycles = get_cycles();	/* start counting the wait time */
+
+	why_wait = RWLOCK_READERS(rwlock_ptr) ?
+			writer_reader_conflict : writer_writer_conflict;
+
+	/* Now set the lock and wait for conflicts to disappear */
+	_raw_write_lock(rwlock_ptr);
+
+	spin_ticks = get_cycles() - start_cycles;
+
+	/* update stats -- if enabled */
+	if (index > 0 && spin_ticks) {
+		if (why_wait == writer_reader_conflict) {
+			/* waited due to a reader holding the lock */
+			write_index = lstat_update_time((void *)rwlock_ptr,
+					this_pc, LSTAT_ACT_SPIN, spin_ticks);
+		} else {
+			/*
+			 * waited due to another writer holding the lock
+			 */
+			write_index = lstat_update_time((void *)rwlock_ptr,
+				this_pc, LSTAT_ACT_WW_SPIN, spin_ticks);
+			(*lstat_control.counts[cpu])[write_index].
+				cum_wait_ww_ticks += spin_ticks;
+			if (spin_ticks >
+				(*lstat_control.counts[cpu])[write_index].
+					max_wait_ww_ticks) {
+				(*lstat_control.counts[cpu])[write_index].
+					max_wait_ww_ticks = spin_ticks;
+			}
+		}
+
+		/* save the directory index for use on write_unlock */
+		(*lstat_control.read_lock_counts[cpu])[index].
+			write_index = write_index;
+	}
+}
+
+void
+_metered_write_unlock(rwlock_t * rwlock_ptr)
+{
+	int index;
+	int cpu;
+	int write_index;
+	uint32_t hold_time;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_write_unlock(rwlock_ptr);
+		return;
+	}
+
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* update statistics if stats enabled for this lock */
+	if (index > 0) {
+		write_index =
+		    (*lstat_control.read_lock_counts[cpu])[index].write_index;
+
+		hold_time = get_cycles() -
+			(*lstat_control.counts[cpu])[write_index].acquire_time;
+		(*lstat_control.counts[cpu])[write_index].cum_hold_ticks +=
+			(uint64_t) hold_time;
+		if ((*lstat_control.counts[cpu])[write_index].max_hold_ticks <
+				hold_time)
+			(*lstat_control.counts[cpu])[write_index].
+				max_hold_ticks = hold_time;
+	}
+	_raw_write_unlock(rwlock_ptr);
+}
+
+int
+_metered_write_trylock(rwlock_t * rwlock_ptr)
+{
+	int retval;
+	void *this_pc = LSTAT_RA(LSTAT_RA_WRITE);
+
+	if ((retval = _raw_write_trylock(rwlock_ptr))) {
+		lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_NO_WAIT);
+	} else {
+		lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_REJECT);
+	}
+
+	return retval;
+}
+
+static void
+init_control_space(void)
+{
+	/* Set all control space pointers to null and indices to "empty" */
+	int cpu;
+
+	/*
+	 * Access CPU_CYCLE_FREQUENCY at the outset, which in some
+	 * architectures may trigger a runtime calculation that uses a
+	 * spinlock.  Let's do this before lockmetering is turned on.
+	 */
+	if (CPU_CYCLE_FREQUENCY == 0)
+		BUG();
+
+	lstat_control.hashtab = NULL;
+	lstat_control.dir = NULL;
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		lstat_control.counts[cpu] = NULL;
+		lstat_control.read_lock_counts[cpu] = NULL;
+	}
+}
+
+static int
+reset_lstat_data(void)
+{
+	int cpu, flags;
+
+	flags = 0;
+	lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+	lstat_control.next_free_read_lock_index = 1;
+	lstat_control.dir_overflow = 0;
+	lstat_control.rwlock_overflow = 0;
+
+	lstat_control.started_cycles64 = 0;
+	lstat_control.ending_cycles64 = 0;
+	lstat_control.enabled_cycles64 = 0;
+	lstat_control.first_started_time = 0;
+	lstat_control.started_time = 0;
+	lstat_control.ending_time = 0;
+	lstat_control.intervals = 0;
+
+	/*
+	 * paranoia -- in case someone does a "lockstat reset" before
+	 * "lockstat on"
+	 */
+	if (lstat_control.hashtab) {
+		bzero(lstat_control.hashtab,
+			LSTAT_HASH_TABLE_SIZE * sizeof (short));
+		bzero(lstat_control.dir, LSTAT_MAX_STAT_INDEX *
+				sizeof (lstat_directory_entry_t));
+
+		for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+			bzero(lstat_control.counts[cpu],
+				sizeof (lstat_cpu_counts_t));
+			bzero(lstat_control.read_lock_counts[cpu],
+				sizeof (lstat_read_lock_cpu_counts_t));
+		}
+	}
+#ifdef NOTDEF
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+#endif
+	return 1;
+}
+
+static void
+release_control_space(void)
+{
+	/*
+	 * Called when either (1) allocation of kmem
+	 * or (2) when user writes LSTAT_RELEASE to /pro/lockmeter.
+	 * Assume that all pointers have been initialized to zero,
+	 * i.e., nonzero pointers are valid addresses.
+	 */
+	int cpu;
+
+	if (lstat_control.hashtab) {
+		kfree(lstat_control.hashtab);
+		lstat_control.hashtab = NULL;
+	}
+
+	if (lstat_control.dir) {
+		vfree(lstat_control.dir);
+		lstat_control.dir = NULL;
+	}
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		if (lstat_control.counts[cpu]) {
+			vfree(lstat_control.counts[cpu]);
+			lstat_control.counts[cpu] = NULL;
+		}
+		if (lstat_control.read_lock_counts[cpu]) {
+			kfree(lstat_control.read_lock_counts[cpu]);
+			lstat_control.read_lock_counts[cpu] = NULL;
+		}
+	}
+}
+
+int
+get_lockmeter_info_size(void)
+{
+	return sizeof (lstat_user_request_t)
+		+ num_online_cpus() * sizeof (lstat_cpu_counts_t)
+		+ num_online_cpus() * sizeof (lstat_read_lock_cpu_counts_t)
+		+ (LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t));
+}
+
+ssize_t
+get_lockmeter_info(char *buffer, size_t max_len, loff_t * last_index)
+{
+	lstat_user_request_t req;
+	struct timeval tv;
+	ssize_t next_ret_bcount;
+	ssize_t actual_ret_bcount = 0;
+	int cpu;
+
+	*last_index = 0;	/* a one-shot read */
+
+	req.lstat_version = LSTAT_VERSION;
+	req.state = lstat_control.state;
+	req.maxcpus = num_online_cpus();
+	req.cycleval = CPU_CYCLE_FREQUENCY;
+#ifdef notyet
+	req.kernel_magic_addr = (void *) &_etext;
+	req.kernel_end_addr = (void *) &_etext;
+#endif
+	req.uts = system_utsname;
+	req.intervals = lstat_control.intervals;
+
+	req.first_started_time = lstat_control.first_started_time;
+	req.started_time = lstat_control.started_time;
+	req.started_cycles64 = lstat_control.started_cycles64;
+
+	req.next_free_dir_index = lstat_control.next_free_dir_index;
+	req.next_free_read_lock_index = lstat_control.next_free_read_lock_index;
+	req.dir_overflow = lstat_control.dir_overflow;
+	req.rwlock_overflow = lstat_control.rwlock_overflow;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		if (req.intervals == 0) {
+			/* mesasurement is off and no valid data present */
+			next_ret_bcount = sizeof (lstat_user_request_t);
+			req.enabled_cycles64 = 0;
+
+			if ((actual_ret_bcount + next_ret_bcount) > max_len)
+				return actual_ret_bcount;
+
+			copy_to_user(buffer, (void *) &req, next_ret_bcount);
+			actual_ret_bcount += next_ret_bcount;
+			return actual_ret_bcount;
+		} else {
+			/*
+			 * measurement is off but valid data present
+			 * fetch time info from lstat_control
+			 */
+			req.ending_time = lstat_control.ending_time;
+			req.ending_cycles64 = lstat_control.ending_cycles64;
+			req.enabled_cycles64 = lstat_control.enabled_cycles64;
+		}
+	} else {
+		/*
+		 * this must be a read while data active--use current time,
+		 * etc
+		 */
+		do_gettimeofday(&tv);
+		req.ending_time = tv.tv_sec;
+		req.ending_cycles64 = get_cycles64();
+		req.enabled_cycles64 = req.ending_cycles64 -
+			req.started_cycles64 + lstat_control.enabled_cycles64;
+	}
+
+	next_ret_bcount = sizeof (lstat_user_request_t);
+	if ((actual_ret_bcount + next_ret_bcount) > max_len)
+		return actual_ret_bcount;
+
+	copy_to_user(buffer, (void *) &req, next_ret_bcount);
+	actual_ret_bcount += next_ret_bcount;
+
+	if (!lstat_control.counts[0])	/* not initialized? */
+		return actual_ret_bcount;
+
+	next_ret_bcount = sizeof (lstat_cpu_counts_t);
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		if ((actual_ret_bcount + next_ret_bcount) > max_len)
+			return actual_ret_bcount;	/* leave early */
+		copy_to_user(buffer + actual_ret_bcount,
+				lstat_control.counts[cpu], next_ret_bcount);
+		actual_ret_bcount += next_ret_bcount;
+	}
+
+	next_ret_bcount = LSTAT_MAX_STAT_INDEX *
+			sizeof (lstat_directory_entry_t);
+	if (((actual_ret_bcount + next_ret_bcount) > max_len)
+			|| !lstat_control.dir)
+		return actual_ret_bcount;	/* leave early */
+
+	copy_to_user(buffer + actual_ret_bcount, lstat_control.dir,
+			next_ret_bcount);
+	actual_ret_bcount += next_ret_bcount;
+
+	next_ret_bcount = sizeof (lstat_read_lock_cpu_counts_t);
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		if (actual_ret_bcount + next_ret_bcount > max_len)
+			return actual_ret_bcount;
+		copy_to_user(buffer + actual_ret_bcount,
+				lstat_control.read_lock_counts[cpu],
+				next_ret_bcount);
+		actual_ret_bcount += next_ret_bcount;
+	}
+
+	return actual_ret_bcount;
+}
+
+/*
+ *  Writing to the /proc lockmeter node enables or disables metering.
+ *  based upon the first byte of the "written" data.
+ *  The following values are defined:
+ *  LSTAT_ON: 1st call: allocates storage, intializes and turns on measurement
+ *            subsequent calls just turn on measurement
+ *  LSTAT_OFF: turns off measurement
+ *  LSTAT_RESET: resets statistics
+ *  LSTAT_RELEASE: releases statistics storage
+ *
+ *  This allows one to accumulate statistics over several lockstat runs:
+ *
+ *  lockstat on
+ *  lockstat off
+ *  ...repeat above as desired...
+ *  lockstat get
+ *  ...now start a new set of measurements...
+ *  lockstat reset
+ *  lockstat on
+ *  ...
+ *
+ */
+ssize_t
+put_lockmeter_info(const char *buffer, size_t len)
+{
+	int error = 0;
+	int dirsize, countsize, read_lock_countsize, hashsize;
+	int cpu;
+	char put_char;
+	int i, read_lock_blocks;
+	unsigned long flags;
+	rwlock_t *lock_ptr;
+	struct timeval tv;
+
+	if (len <= 0)
+		return -EINVAL;
+
+	_raw_spin_lock(&lstat_control.control_lock);
+
+	get_user(put_char, buffer);
+	switch (put_char) {
+
+	case LSTAT_OFF:
+		if (lstat_control.state != LSTAT_OFF) {
+			/*
+			 * To avoid seeing read lock hold times in an
+			 * inconsisent state, we have to follow this protocol
+			 * to turn off statistics
+			 */
+			local_irq_save(flags);
+			/*
+			 * getting this lock will stop any read lock block
+			 * allocations
+			 */
+			_raw_spin_lock(&lstat_control.directory_lock);
+			/*
+			 * keep any more read lock blocks from being
+			 * allocated
+			 */
+			lstat_control.state = LSTAT_OFF;
+			/* record how may read lock blocks there are */
+			read_lock_blocks =
+				lstat_control.next_free_read_lock_index;
+			_raw_spin_unlock(&lstat_control.directory_lock);
+			/* now go through the list of read locks */
+			cpu = THIS_CPU_NUMBER;
+			for (i = 1; i < read_lock_blocks; i++) {
+				lock_ptr =
+				    (*lstat_control.read_lock_counts[cpu])[i].
+				    lock_ptr;
+				/* is this saved lock address still valid? */
+				if (GET_RWINDEX(lock_ptr) == i) {
+					/*
+					 * lock address appears to still be
+					 * valid because we only hold one lock
+					 * at a time, this can't cause a
+					 * deadlock unless this is a lock held
+					 * as part of the current system call
+					 * path. At the moment there
+					 * are no READ mode locks held to get
+					 * here from user space, so we solve
+					 * this by skipping locks held in
+					 * write mode.
+					 */
+					if (RWLOCK_IS_WRITE_LOCKED(lock_ptr)) {
+						PUT_RWINDEX(lock_ptr, 0);
+						continue;
+					}
+					/*
+					 * now we know there are no read
+					 * holders of this lock! stop
+					 * statistics collection for this
+					 * lock
+					 */
+					_raw_write_lock(lock_ptr);
+					PUT_RWINDEX(lock_ptr, 0);
+					_raw_write_unlock(lock_ptr);
+				}
+				/*
+				 * it may still be possible for the hold time
+				 * sum to be negative e.g. if a lock is
+				 * reallocated while "busy" we will have to fix
+				 * this up in the data reduction program.
+				 */
+			}
+			local_irq_restore(flags);
+			lstat_control.intervals++;
+			lstat_control.ending_cycles64 = get_cycles64();
+			lstat_control.enabled_cycles64 +=
+				lstat_control.ending_cycles64 -
+				lstat_control.started_cycles64;
+			do_gettimeofday(&tv);
+			lstat_control.ending_time = tv.tv_sec;
+			/*
+			 * don't deallocate the structures -- we may do a
+			 * lockstat on to add to the data that is already
+			 * there. Use LSTAT_RELEASE to release storage
+			 */
+		} else {
+			error = -EBUSY;	/* already OFF */
+		}
+		break;
+
+	case LSTAT_ON:
+		if (lstat_control.state == LSTAT_OFF) {
+#ifdef DEBUG_LOCKMETER
+			printk("put_lockmeter_info(cpu=%d): LSTAT_ON\n",
+				THIS_CPU_NUMBER);
+#endif
+			lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+
+			dirsize = LSTAT_MAX_STAT_INDEX *
+					sizeof (lstat_directory_entry_t);
+			hashsize =
+				(1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
+			countsize = sizeof (lstat_cpu_counts_t);
+			read_lock_countsize =
+				sizeof (lstat_read_lock_cpu_counts_t);
+#ifdef DEBUG_LOCKMETER
+			printk(" dirsize:%d", dirsize);
+			printk(" hashsize:%d", hashsize);
+			printk(" countsize:%d", countsize);
+			printk(" read_lock_countsize:%d\n",
+				read_lock_countsize);
+#endif
+#ifdef DEBUG_LOCKMETER
+			{
+				int secs;
+				unsigned long cycles;
+				uint64_t cycles64;
+
+				do_gettimeofday(&tv);
+				secs = tv.tv_sec;
+				do {
+					do_gettimeofday(&tv);
+				} while (secs == tv.tv_sec);
+				cycles = get_cycles();
+				cycles64 = get_cycles64();
+				secs = tv.tv_sec;
+				do {
+					do_gettimeofday(&tv);
+				} while (secs == tv.tv_sec);
+				cycles = get_cycles() - cycles;
+				cycles64 = get_cycles64() - cycles;
+				printk("lockmeter: cycleFrequency:%d "
+					"cycles:%d cycles64:%d\n",
+					CPU_CYCLE_FREQUENCY, cycles, cycles64);
+			}
+#endif
+
+			/*
+			 * if this is the first call, allocate storage and
+			 * initialize
+			 */
+			if (!lstat_control.hashtab) {
+
+				spin_lock_init(&lstat_control.directory_lock);
+
+				/* guarantee all pointers at zero */
+				init_control_space();
+
+				lstat_control.hashtab =
+				    kmalloc(hashsize, GFP_KERNEL);
+				if (!lstat_control.hashtab) {
+					error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+					printk("!!error kmalloc of hashtab\n");
+#endif
+				}
+				lstat_control.dir = vmalloc(dirsize);
+				if (!lstat_control.dir) {
+					error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+					printk("!!error kmalloc of dir\n");
+#endif
+				}
+
+				for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+					lstat_control.counts[cpu] =
+						vmalloc(countsize);
+					if (!lstat_control.counts[cpu]) {
+						error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+						printk("!!error vmalloc of "
+							"counts[%d]\n", cpu);
+#endif
+					}
+					lstat_control.read_lock_counts[cpu] =
+						(lstat_read_lock_cpu_counts_t *)
+						kmalloc(read_lock_countsize,
+							GFP_KERNEL);
+					if (!lstat_control.
+							read_lock_counts[cpu]) {
+						error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+						printk("!!error kmalloc of "
+						  "read_lock_counts[%d]\n",
+							cpu);
+#endif
+					}
+				}
+			}
+
+			if (error) {
+				/*
+				 * One or more kmalloc failures -- free
+				 * everything
+				 */
+				release_control_space();
+			} else {
+
+				if (!reset_lstat_data()) {
+					error = -EINVAL;
+					break;
+				};
+
+				/*
+				 * record starting and ending times and the
+				 * like
+				 */
+				if (lstat_control.intervals == 0) {
+					do_gettimeofday(&tv);
+					lstat_control.first_started_time =
+						tv.tv_sec;
+				}
+				lstat_control.started_cycles64 = get_cycles64();
+				do_gettimeofday(&tv);
+				lstat_control.started_time = tv.tv_sec;
+
+				lstat_control.state = LSTAT_ON;
+			}
+		} else {
+			error = -EBUSY;	/* already ON */
+		}
+		break;
+
+	case LSTAT_RESET:
+		if (lstat_control.state == LSTAT_OFF) {
+			if (!reset_lstat_data())
+				error = -EINVAL;
+		} else {
+			error = -EBUSY;	/* still on; can't reset */
+		}
+		break;
+
+	case LSTAT_RELEASE:
+		if (lstat_control.state == LSTAT_OFF) {
+			release_control_space();
+			lstat_control.intervals = 0;
+			lstat_control.enabled_cycles64 = 0;
+		} else {
+			error = -EBUSY;
+		}
+		break;
+
+	default:
+		error = -EINVAL;
+	}			/* switch */
+
+	_raw_spin_unlock(&lstat_control.control_lock);
+	return error ? error : len;
+}
+
+#ifdef USER_MODE_TESTING
+/* following used for user mode testing */
+void
+lockmeter_init()
+{
+	int dirsize, hashsize, countsize, read_lock_countsize, cpu;
+
+	printf("lstat_control is at %x size=%d\n", &lstat_control,
+		sizeof (lstat_control));
+	printf("sizeof(spinlock_t)=%d\n", sizeof (spinlock_t));
+	lstat_control.state = LSTAT_ON;
+
+	lstat_control.directory_lock = SPIN_LOCK_UNLOCKED;
+	lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+	lstat_control.next_free_read_lock_index = 1;
+
+	dirsize = LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t);
+	hashsize = (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
+	countsize = sizeof (lstat_cpu_counts_t);
+	read_lock_countsize = sizeof (lstat_read_lock_cpu_counts_t);
+
+	lstat_control.hashtab = (ushort *) malloc(hashsize);
+
+	if (lstat_control.hashtab == 0) {
+		printf("malloc failure for at line %d in lockmeter.c\n",
+			__LINE__);
+		exit(0);
+	}
+
+	lstat_control.dir = (lstat_directory_entry_t *) malloc(dirsize);
+
+	if (lstat_control.dir == 0) {
+		printf("malloc failure for at line %d in lockmeter.c\n", cpu,
+			__LINE__);
+		exit(0);
+	}
+
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		int j, k;
+		j = (int) (lstat_control.counts[cpu] =
+			   (lstat_cpu_counts_t *) malloc(countsize));
+		k = (int) (lstat_control.read_lock_counts[cpu] =
+			   (lstat_read_lock_cpu_counts_t *)
+			   malloc(read_lock_countsize));
+		if (j * k == 0) {
+			printf("malloc failure for cpu=%d at line %d in "
+				"lockmeter.c\n", cpu, __LINE__);
+			exit(0);
+		}
+	}
+
+	memset(lstat_control.hashtab, 0, hashsize);
+	memset(lstat_control.dir, 0, dirsize);
+
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		memset(lstat_control.counts[cpu], 0, countsize);
+		memset(lstat_control.read_lock_counts[cpu], 0,
+			read_lock_countsize);
+	}
+}
+
+asm(" \
+.align	4 \
+.globl	__write_lock_failed \
+__write_lock_failed: \
+	" LOCK "addl	$" RW_LOCK_BIAS_STR ",(%eax) \
+1:	cmpl	$" RW_LOCK_BIAS_STR ",(%eax) \
+	jne	1b \
+\
+	" LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax) \
+	jnz	__write_lock_failed \
+	ret \
+\
+\
+.align	4 \
+.globl	__read_lock_failed \
+__read_lock_failed: \
+	lock ; incl	(%eax) \
+1:	cmpl	$1,(%eax) \
+	js	1b \
+\
+	lock ; decl	(%eax) \
+	js	__read_lock_failed \
+	ret \
+");
+#endif
+
+EXPORT_SYMBOL(_metered_spin_lock);
+EXPORT_SYMBOL(_metered_spin_unlock);
+EXPORT_SYMBOL(_metered_spin_trylock);
+EXPORT_SYMBOL(_metered_read_lock);
+EXPORT_SYMBOL(_metered_read_unlock);
+EXPORT_SYMBOL(_metered_write_lock);
+EXPORT_SYMBOL(_metered_write_unlock);
--- diff/lib/qsort.c	1970-01-01 01:00:00.000000000 +0100
+++ source/lib/qsort.c	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,239 @@
+/*
+ * qsort implementation for the Linux kernel.
+ *
+ * Original implementation taken form glibc and credited to Douglas
+ * C. Schmidt (schmidt@ics.uci.edu).
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+/*
+ * If you consider tuning this algorithm, you should consult first:
+ * Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
+ * Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993.
+ */
+
+# include <linux/module.h>
+# include <linux/slab.h>
+# include <linux/string.h>
+
+MODULE_LICENSE("GPL");
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(a, b, size)		      \
+  do {					      \
+      size_t __size = (size);		      \
+      char *__a = (a), *__b = (b);	      \
+      do {				      \
+	  char __tmp = *__a;		      \
+	  *__a++ = *__b;		      \
+	  *__b++ = __tmp;		      \
+	} while (--__size > 0);		      \
+    } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this
+   size.  This particular magic number was chosen to work best on a
+   Sun 4/260. */
+#define MAX_THRESH 4
+
+/* Stack node declarations used to store unfulfilled partition
+ * obligations. */
+typedef struct {
+	char *lo;
+	char *hi;
+} stack_node;
+
+/* The next 5 #defines implement a very fast in-line stack
+ * abstraction.  The stack needs log (total_elements) entries (we
+ * could even subtract log(MAX_THRESH)).  Since total_elements has
+ * type size_t, we get as upper bound for log (total_elements): bits
+ * per byte (CHAR_BIT) * sizeof(size_t).  */
+
+#define CHAR_BIT 8
+#define STACK_SIZE	(CHAR_BIT * sizeof(size_t))
+#define PUSH(low, high)	((top->lo = (low)), (top->hi = (high)), ++top)
+#define	POP(low, high)	(--top, (low = top->lo), (high = top->hi))
+#define	STACK_NOT_EMPTY	(stack < top)
+
+/* Order size using quicksort.  This implementation incorporates four
+   optimizations discussed in Sedgewick:
+
+   1. Non-recursive, using an explicit stack of pointer that store the
+   next array partition to sort.  To save time, this maximum amount
+   of space required to store an array of SIZE_MAX is allocated on
+   the stack.  Assuming a 32-bit (64 bit) integer for size_t, this
+   needs only 32 * sizeof(stack_node) == 256 bytes (for 64 bit:
+   1024 bytes).  Pretty cheap, actually.
+
+   2. Chose the pivot element using a median-of-three decision tree.
+   This reduces the probability of selecting a bad pivot value and
+   eliminates certain extraneous comparisons.
+
+   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+   insertion sort to order the MAX_THRESH items within each
+   partition.  This is a big win, since insertion sort is faster
+   for small, mostly sorted array segments.
+
+   4. The larger of the two sub-partitions is always pushed onto the
+   stack first, with the algorithm then concentrating on the
+   smaller partition.  This *guarantees* no more than log
+   (total_elems) stack size is needed (actually O(1) in this case)!
+*/
+
+void
+qsort(void *const pbase, size_t total_elems, size_t size,
+      int (*cmp)(const void*, const void*))
+{
+	char *base_ptr = (char *)pbase;
+
+	const size_t max_thresh = MAX_THRESH * size;
+
+	/* Avoid lossage with unsigned arithmetic below.  */
+	if (total_elems == 0) {
+		return;
+	}
+
+	if (total_elems > MAX_THRESH) {
+		char *lo = base_ptr;
+		char *hi = &lo[size * (total_elems - 1)];
+		stack_node stack[STACK_SIZE];
+		stack_node *top = stack + 1;
+
+		while (STACK_NOT_EMPTY) {
+			char *left_ptr;
+			char *right_ptr;
+
+			/* Select median value from among LO, MID, and
+			   HI. Rearrange LO and HI so the three values
+			   are sorted. This lowers the probability of
+			   picking a pathological pivot value and
+			   skips a comparison for both the LEFT_PTR
+			   and RIGHT_PTR in the while loops. */
+
+			char *mid = lo + size * ((hi - lo) / size >> 1);
+
+			if ((*cmp)((void*)mid, (void*)lo) < 0)
+				SWAP(mid, lo, size);
+			if ((*cmp)((void*)hi, (void*)mid) < 0)
+				SWAP(mid, hi, size);
+			else
+				goto jump_over;
+			if ((*cmp)((void*)mid, (void*)lo) < 0)
+				SWAP(mid, lo, size);
+		jump_over:
+
+			left_ptr = lo + size;
+			right_ptr = hi - size;
+
+			/* Here's the famous ``collapse the walls''
+			   section of quicksort.  Gotta like those
+			   tight inner loops!  They are the main
+			   reason that this algorithm runs much faster
+			   than others. */
+			do {
+				while ((*cmp)((void*)left_ptr, (void*)mid) < 0)
+					left_ptr += size;
+
+				while ((*cmp)((void*)mid, (void*)right_ptr) < 0)
+					right_ptr -= size;
+
+				if (left_ptr < right_ptr) {
+					SWAP(left_ptr, right_ptr, size);
+					if (mid == left_ptr)
+						mid = right_ptr;
+					else if (mid == right_ptr)
+						mid = left_ptr;
+					left_ptr += size;
+					right_ptr -= size;
+				} else if (left_ptr == right_ptr) {
+					left_ptr += size;
+					right_ptr -= size;
+					break;
+				}
+			}
+			while (left_ptr <= right_ptr);
+
+			/* Set up pointers for next iteration.  First
+			   determine whether left and right partitions
+			   are below the threshold size.  If so,
+			   ignore one or both.  Otherwise, push the
+			   larger partition's bounds on the stack and
+			   continue sorting the smaller one. */
+
+			if ((size_t) (right_ptr - lo) <= max_thresh) {
+				if ((size_t) (hi - left_ptr) <= max_thresh)
+					/* Ignore both small partitions. */
+					POP(lo, hi);
+				else
+					/* Ignore small left partition. */
+					lo = left_ptr;
+			} else if ((size_t) (hi - left_ptr) <= max_thresh)
+				/* Ignore small right partition. */
+				hi = right_ptr;
+			else if ((right_ptr - lo) > (hi - left_ptr)) {
+				/* Push larger left partition indices. */
+				PUSH(lo, right_ptr);
+				lo = left_ptr;
+			} else {
+				/* Push larger right partition indices. */
+				PUSH(left_ptr, hi);
+				hi = right_ptr;
+			}
+		}
+	}
+
+	/* Once the BASE_PTR array is partially sorted by quicksort
+	   the rest is completely sorted using insertion sort, since
+	   this is efficient for partitions below MAX_THRESH
+	   size. BASE_PTR points to the beginning of the array to
+	   sort, and END_PTR points at the very last element in the
+	   array (*not* one beyond it!). */
+
+	{
+		char *end_ptr = &base_ptr[size * (total_elems - 1)];
+		char *tmp_ptr = base_ptr;
+		char *thresh = min(end_ptr, base_ptr + max_thresh);
+		char *run_ptr;
+
+		/* Find smallest element in first threshold and place
+		   it at the array's beginning.  This is the smallest
+		   array element, and the operation speeds up
+		   insertion sort's inner loop. */
+
+		for (run_ptr = tmp_ptr + size; run_ptr <= thresh;
+				run_ptr += size)
+			if ((*cmp)((void*)run_ptr, (void*)tmp_ptr) < 0)
+				tmp_ptr = run_ptr;
+
+		if (tmp_ptr != base_ptr)
+			SWAP(tmp_ptr, base_ptr, size);
+
+		/* Insertion sort, running from left-hand-side up to
+		 * right-hand-side.  */
+
+		run_ptr = base_ptr + size;
+		while ((run_ptr += size) <= end_ptr) {
+			tmp_ptr = run_ptr - size;
+			while ((*cmp)((void*)run_ptr, (void*)tmp_ptr) < 0)
+				tmp_ptr -= size;
+
+			tmp_ptr += size;
+			if (tmp_ptr != run_ptr) {
+				char *trav;
+
+				trav = run_ptr + size;
+				while (--trav >= run_ptr) {
+					char c = *trav;
+					char *hi, *lo;
+
+					for (hi = lo = trav;
+					     (lo -= size) >= tmp_ptr; hi = lo)
+						*hi = *lo;
+					*hi = c;
+				}
+			}
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(qsort);
--- diff/scripts/checkstack.pl	1970-01-01 01:00:00.000000000 +0100
+++ source/scripts/checkstack.pl	2004-05-27 18:34:20.000000000 +0100
@@ -0,0 +1,101 @@
+#!/usr/bin/perl
+
+#	Check the stack usage of functions
+#
+#	Copyright Joern Engel <joern@wh.fh-wedel.de>
+#	Inspired by Linus Torvalds
+#	Original idea maybe from Keith Owens
+#	s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
+#	Mips port by Juan Quintela <quintela@mandrakesoft.com>
+#	IA64 port via Andreas Dilger
+#	Arm port by Holger Schurig
+#	Random bits by Matt Mackall <mpm@selenic.com>
+#
+#	Usage:
+#	objdump -d vmlinux | stackcheck_ppc.pl [arch]
+#
+#	TODO :	Port to all architectures (one regex per arch)
+
+# check for arch
+#
+# $re is used for two matches:
+# $& (whole re) matches the complete objdump line with the stack growth
+# $1 (first bracket) matches the size of the stack growth
+#
+# use anything else and feel the pain ;)
+{
+	my $arch = shift;
+	if ($arch eq "") {
+		$arch = `uname -m`;
+	}
+
+	$x	= "[0-9a-f]";	# hex character
+	$xs	= "[0-9a-f ]";	# hex character or space
+	if ($arch =~ /^arm$/) {
+		#c0008ffc:	e24dd064	sub	sp, sp, #100	; 0x64
+		$re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
+	} elsif ($arch =~ /^i[3456]86$/) {
+		#c0105234:       81 ec ac 05 00 00       sub    $0x5ac,%esp
+		$re = qr/^.*sub    \$(0x$x{3,5}),\%esp$/o;
+	} elsif ($arch =~ /^ia64$/) {
+		#e0000000044011fc:       01 0f fc 8c     adds r12=-384,r12
+		$re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
+	} elsif ($arch =~ /^mips64$/) {
+		#8800402c:       67bdfff0        daddiu  sp,sp,-16
+		$re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+	} elsif ($arch =~ /^mips$/) {
+		#88003254:       27bdffe0        addiu   sp,sp,-32
+		$re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+	} elsif ($arch =~ /^ppc$/) {
+		#c00029f4:       94 21 ff 30     stwu    r1,-208(r1)
+		$re = qr/.*stwu.*r1,-($x{3,5})\(r1\)/o;
+	} elsif ($arch =~ /^ppc64$/) {
+		#XXX
+		$re = qr/.*stdu.*r1,-($x{3,5})\(r1\)/o;
+	} elsif ($arch =~ /^s390x?$/) {
+		#   11160:       a7 fb ff 60             aghi   %r15,-160
+		$re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+	} else {
+		print("wrong or unknown architecture\n");
+		exit
+	}
+}
+
+sub bysize($) {
+	($asize = $a) =~ s/.*	+(.*)$/$1/;
+	($bsize = $b) =~ s/.*	+(.*)$/$1/;
+	$bsize <=> $asize
+}
+
+#
+# main()
+#
+$funcre = qr/^$x* \<(.*)\>:$/;
+while ($line = <STDIN>) {
+	if ($line =~ m/$funcre/) {
+		$func = $1;
+	}
+	if ($line =~ m/$re/) {
+		my $size = $1;
+		$size = hex($size) if ($size =~ /^0x/);
+
+		$line =~ m/^($xs*).*/;
+		my $addr = $1;
+		$addr =~ s/ /0/g;
+		$addr = "0x$addr";
+
+		my $intro = "$addr $func:";
+		my $padlen = 56 - length($intro);
+		while ($padlen > 0) {
+			$intro .= '	';
+			$padlen -= 8;
+		}
+		$stack[@stack] = "$intro$size\n";
+	}
+}
+
+@sortedstack = sort bysize @stack;
+
+foreach $i (@sortedstack) {
+	print("$i");
+}
--- diff/arch/i386/kernel/std_resources.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/std_resources.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,204 +0,0 @@
-/*
- *  Machine specific resource allocation for generic.
- */
-
-#include <linux/ioport.h>
-#include <asm/io.h>
-#include <asm/std_resources.h>
-
-#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
-
-static struct resource system_rom_resource = {
-	.name	= "System ROM",
-	.start	= 0xf0000,
-	.end	= 0xfffff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-static struct resource extension_rom_resource = {
-	.name	= "Extension ROM",
-	.start	= 0xe0000,
-	.end	= 0xeffff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-static struct resource adapter_rom_resources[] = { {
-	.name 	= "Adapter ROM",
-	.start	= 0xc8000,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-} };
-
-#define ADAPTER_ROM_RESOURCES \
-	(sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
-
-static struct resource video_rom_resource = {
-	.name 	= "Video ROM",
-	.start	= 0xc0000,
-	.end	= 0xc7fff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-static struct resource vram_resource = {
-	.name	= "Video RAM area",
-	.start	= 0xa0000,
-	.end	= 0xbffff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM
-};
-
-static struct resource standard_io_resources[] = { {
-	.name	= "dma1",
-	.start	= 0x0000,
-	.end	= 0x001f,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "pic1",
-	.start	= 0x0020,
-	.end	= 0x0021,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "timer",
-	.start	= 0x0040,
-	.end	= 0x005f,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "keyboard",
-	.start	= 0x0060,
-	.end	= 0x006f,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "dma page reg",
-	.start	= 0x0080,
-	.end	= 0x008f,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "pic2",
-	.start	= 0x00a0,
-	.end	= 0x00a1,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "dma2",
-	.start	= 0x00c0,
-	.end	= 0x00df,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "fpu",
-	.start	= 0x00f0,
-	.end	= 0x00ff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-} };
-
-#define STANDARD_IO_RESOURCES \
-	(sizeof standard_io_resources / sizeof standard_io_resources[0])
-
-static int __init checksum(unsigned char *rom, unsigned long length)
-{
-	unsigned char *p, sum = 0;
-
-	for (p = rom; p < rom + length; p++)
-		sum += *p;
-	return sum == 0;
-}
-
-void __init probe_roms(void)
-{
-	unsigned long start, length, upper;
-	unsigned char *rom;
-	int	      i;
-
-	/* video rom */
-	upper = adapter_rom_resources[0].start;
-	for (start = video_rom_resource.start; start < upper; start += 2048) {
-		rom = isa_bus_to_virt(start);
-		if (!romsignature(rom))
-			continue;
-
-		video_rom_resource.start = start;
-
-		/* 0 < length <= 0x7f * 512, historically */
-		length = rom[2] * 512;
-
-		/* if checksum okay, trust length byte */
-		if (length && checksum(rom, length))
-			video_rom_resource.end = start + length - 1;
-
-		request_resource(&iomem_resource, &video_rom_resource);
-		break;
-	}
-
-	start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
-	if (start < upper)
-		start = upper;
-
-	/* system rom */
-	request_resource(&iomem_resource, &system_rom_resource);
-	upper = system_rom_resource.start;
-
-	/* check for extension rom (ignore length byte!) */
-	rom = isa_bus_to_virt(extension_rom_resource.start);
-	if (romsignature(rom)) {
-		length = extension_rom_resource.end - extension_rom_resource.start + 1;
-		if (checksum(rom, length)) {
-			request_resource(&iomem_resource, &extension_rom_resource);
-			upper = extension_rom_resource.start;
-		}
-	}
-
-	/* check for adapter roms on 2k boundaries */
-	for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
-		rom = isa_bus_to_virt(start);
-		if (!romsignature(rom))
-			continue;
-
-		/* 0 < length <= 0x7f * 512, historically */
-		length = rom[2] * 512;
-
-		/* but accept any length that fits if checksum okay */
-		if (!length || start + length > upper || !checksum(rom, length))
-			continue;
-
-		adapter_rom_resources[i].start = start;
-		adapter_rom_resources[i].end = start + length - 1;
-		request_resource(&iomem_resource, &adapter_rom_resources[i]);
-
-		start = adapter_rom_resources[i++].end & ~2047UL;
-	}
-}
-
-void __init request_graphics_resource(void)
-{
-	request_resource(&iomem_resource, &vram_resource);
-}
-
-void __init request_standard_io_resources(void)
-{
-	int i;
-
-	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
-		request_resource(&ioport_resource, &standard_io_resources[i]);
-}
--- diff/drivers/usb/core/driverfs.c	2004-05-19 22:12:16.000000000 +0100
+++ source/drivers/usb/core/driverfs.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,229 +0,0 @@
-/*
- * drivers/usb/core/driverfs.c
- *
- * (C) Copyright 2002 David Brownell
- * (C) Copyright 2002 Greg Kroah-Hartman
- * (C) Copyright 2002 IBM Corp.
- *
- * All of the driverfs file attributes for usb devices and interfaces.
- *
- */
-
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-
-#ifdef CONFIG_USB_DEBUG
-	#define DEBUG
-#else
-	#undef DEBUG
-#endif
-#include <linux/usb.h>
-
-#include "usb.h"
-
-/* Active configuration fields */
-#define usb_actconfig_show(field, multiplier, format_string)		\
-static ssize_t  show_##field (struct device *dev, char *buf)		\
-{									\
-	struct usb_device *udev;					\
-									\
-	udev = to_usb_device (dev);					\
-	if (udev->actconfig)						\
-		return sprintf (buf, format_string,			\
-				udev->actconfig->desc.field * multiplier);	\
-	else								\
-		return 0;						\
-}									\
-
-#define usb_actconfig_attr(field, multiplier, format_string)		\
-usb_actconfig_show(field, multiplier, format_string)			\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-
-usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr (bmAttributes, 1, "%2x\n")
-usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
-
-/* configuration value is always present, and r/w */
-usb_actconfig_show(bConfigurationValue, 1, "%u\n");
-
-static ssize_t
-set_bConfigurationValue (struct device *dev, const char *buf, size_t count)
-{
-	struct usb_device	*udev = udev = to_usb_device (dev);
-	int			config, value;
-
-	if (sscanf (buf, "%u", &config) != 1 || config > 255)
-		return -EINVAL;
-	down(&udev->serialize);
-	value = usb_set_configuration (udev, config);
-	up(&udev->serialize);
-	return (value < 0) ? value : count;
-}
-
-static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, 
-		show_bConfigurationValue, set_bConfigurationValue);
-
-/* String fields */
-#define usb_string_attr(name, field)		\
-static ssize_t  show_##name(struct device *dev, char *buf)		\
-{									\
-	struct usb_device *udev;					\
-	int len;							\
-									\
-	udev = to_usb_device (dev);					\
-	len = usb_string(udev, udev->descriptor.field, buf, PAGE_SIZE);	\
-	if (len < 0)							\
-		return 0;						\
-	buf[len] = '\n';						\
-	buf[len+1] = 0;							\
-	return len+1;							\
-}									\
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-usb_string_attr(product, iProduct);
-usb_string_attr(manufacturer, iManufacturer);
-usb_string_attr(serial, iSerialNumber);
-
-static ssize_t
-show_speed (struct device *dev, char *buf)
-{
-	struct usb_device *udev;
-	char *speed;
-
-	udev = to_usb_device (dev);
-
-	switch (udev->speed) {
-	case USB_SPEED_LOW:
-		speed = "1.5";
-		break;
-	case USB_SPEED_UNKNOWN:
-	case USB_SPEED_FULL:
-		speed = "12";
-		break;
-	case USB_SPEED_HIGH:
-		speed = "480";
-		break;
-	default:
-		speed = "unknown";
-	}
-	return sprintf (buf, "%s\n", speed);
-}
-static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
-
-static ssize_t
-show_devnum (struct device *dev, char *buf)
-{
-	struct usb_device *udev;
-
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%d\n", udev->devnum);
-}
-static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
-
-static ssize_t
-show_version (struct device *dev, char *buf)
-{
-	struct usb_device *udev;
-
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%2x.%02x\n", udev->descriptor.bcdUSB >> 8, 
-			udev->descriptor.bcdUSB & 0xff);
-}
-static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
-
-static ssize_t
-show_maxchild (struct device *dev, char *buf)
-{
-	struct usb_device *udev;
-
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%d\n", udev->maxchild);
-}
-static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
-
-/* Descriptor fields */
-#define usb_descriptor_attr(field, format_string)			\
-static ssize_t								\
-show_##field (struct device *dev, char *buf)				\
-{									\
-	struct usb_device *udev;					\
-									\
-	udev = to_usb_device (dev);					\
-	return sprintf (buf, format_string, udev->descriptor.field);	\
-}									\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-
-usb_descriptor_attr (idVendor, "%04x\n")
-usb_descriptor_attr (idProduct, "%04x\n")
-usb_descriptor_attr (bcdDevice, "%04x\n")
-usb_descriptor_attr (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-
-
-void usb_create_driverfs_dev_files (struct usb_device *udev)
-{
-	struct device *dev = &udev->dev;
-
-	/* current configuration's attributes */
-	device_create_file (dev, &dev_attr_bNumInterfaces);
-	device_create_file (dev, &dev_attr_bConfigurationValue);
-	device_create_file (dev, &dev_attr_bmAttributes);
-	device_create_file (dev, &dev_attr_bMaxPower);
-
-	/* device attributes */
-	device_create_file (dev, &dev_attr_idVendor);
-	device_create_file (dev, &dev_attr_idProduct);
-	device_create_file (dev, &dev_attr_bcdDevice);
-	device_create_file (dev, &dev_attr_bDeviceClass);
-	device_create_file (dev, &dev_attr_bDeviceSubClass);
-	device_create_file (dev, &dev_attr_bDeviceProtocol);
-	device_create_file (dev, &dev_attr_bNumConfigurations);
-
-	/* speed varies depending on how you connect the device */
-	device_create_file (dev, &dev_attr_speed);
-	// FIXME iff there are other speed configs, show how many
-
-	if (udev->descriptor.iManufacturer)
-		device_create_file (dev, &dev_attr_manufacturer);
-	if (udev->descriptor.iProduct)
-		device_create_file (dev, &dev_attr_product);
-	if (udev->descriptor.iSerialNumber)
-		device_create_file (dev, &dev_attr_serial);
-
-	device_create_file (dev, &dev_attr_devnum);
-	device_create_file (dev, &dev_attr_version);
-	device_create_file (dev, &dev_attr_maxchild);
-}
-
-/* Interface fields */
-#define usb_intf_attr(field, format_string)				\
-static ssize_t								\
-show_##field (struct device *dev, char *buf)				\
-{									\
-	struct usb_interface *intf = to_usb_interface (dev);		\
-									\
-	return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \
-}									\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-
-usb_intf_attr (bInterfaceNumber, "%02x\n")
-usb_intf_attr (bAlternateSetting, "%2d\n")
-usb_intf_attr (bNumEndpoints, "%02x\n")
-usb_intf_attr (bInterfaceClass, "%02x\n")
-usb_intf_attr (bInterfaceSubClass, "%02x\n")
-usb_intf_attr (bInterfaceProtocol, "%02x\n")
-usb_intf_attr (iInterface, "%02x\n")
-
-void usb_create_driverfs_intf_files (struct usb_interface *intf)
-{
-	device_create_file (&intf->dev, &dev_attr_bInterfaceNumber);
-	device_create_file (&intf->dev, &dev_attr_bAlternateSetting);
-	device_create_file (&intf->dev, &dev_attr_bNumEndpoints);
-	device_create_file (&intf->dev, &dev_attr_bInterfaceClass);
-	device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass);
-	device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol);
-	device_create_file (&intf->dev, &dev_attr_iInterface);
-}
--- diff/include/asm-i386/std_resources.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/std_resources.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,14 +0,0 @@
-/*
- * include/asm-i386/std_resources.h
- */
-
-#ifndef __ASM_I386_STD_RESOURCES_H
-#define __ASM_I386_STD_RESOURCES_H
-
-#include <linux/init.h>
-
-void probe_roms(void) __init;
-void request_graphics_resource(void) __init;
-void request_standard_io_resources(void) __init;
-
-#endif
--- diff/sound/pci/ice1712/prodigy.c	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/prodigy.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,663 +0,0 @@
-/*
- *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
- *
- *   Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards
- *      Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca>
- *	based on the aureon.c code (c) 2003 by Takashi Iwai <tiwai@suse.de>
- *
- *   version 0.82: Stable / not all features work yet (no communication with AC97 secondary)
- *       added 64x/128x oversampling switch (should be 64x only for 96khz)
- *       fixed some recording labels (still need to check the rest)
- *       recording is working probably thanks to correct wm8770 initialization
- *
- *   version 0.5: Initial release:
- *           working: analog output, mixer, headphone amplifier switch
- *       not working: prety much everything else, at least i could verify that
- *                    we have no digital output, no capture, pretty bad clicks and poops
- *                    on mixer switch and other coll stuff.
- *
- *   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
- *
- *
- * NOTES:
- *
- *
- *
- * - we reuse the akm4xxx_t record for storing the wm8770 codec data.
- *   both wm and akm codecs are pretty similar, so we can integrate
- *   both controls in the future, once if wm codecs are reused in
- *   many boards.
- *
- * - writing over SPI is implemented but reading is not yet.
- *   the SPDIF-in channel status, etc. can be read from CS chip.
- *
- * - DAC digital volumes are not implemented in the mixer.
- *   if they show better response than DAC analog volumes, we can use them
- *   instead.
- *
- * - Prodigy boards are equipped with AC97 STAC9744 chip , too.  it's used to do
- *   the analog mixing but not easily controllable (it's not connected
- *   directly from envy24ht chip).  so let's leave it as it is.
- *
- */
-
-#define REVISION 0.82b
-
-#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 "prodigy.h"
-
-
-static int prodigy_set_headphone_amp(ice1712_t *ice, int enable)
-{
-	unsigned int tmp, tmp2;
-
-	tmp2 = tmp = snd_ice1712_gpio_read(ice);
-	if (enable)
-		tmp |= PRODIGY_HP_AMP_EN;
-	else
-		tmp &= ~ PRODIGY_HP_AMP_EN;
-	if (tmp != tmp2) {
-		snd_ice1712_gpio_write(ice, tmp);
-		return 1;
-	}
-	return 0;
-}
-
-
-static int prodigy_get_headphone_amp(ice1712_t *ice)
-{
-	unsigned int tmp = snd_ice1712_gpio_read(ice);
-
-	return ( tmp & PRODIGY_HP_AMP_EN )!= 0;
-}
-
-
-/*
- * write data in the SPI mode
- */
-static void prodigy_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits)
-{
-	unsigned int tmp;
-	int i;
-
-	tmp = snd_ice1712_gpio_read(ice);
-
-	snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_WM_RW|PRODIGY_WM_DATA|PRODIGY_WM_CLK|
-					 PRODIGY_WM_CS|PRODIGY_CS8415_CS|PRODIGY_HP_AMP_EN));
-	tmp |= PRODIGY_WM_RW;
-	tmp &= ~cs;
-	snd_ice1712_gpio_write(ice, tmp);
-	udelay(1);
-
-	for (i = bits - 1; i >= 0; i--) {
-		tmp &= ~PRODIGY_WM_CLK;
-		snd_ice1712_gpio_write(ice, tmp);
-		udelay(1);
-		if (data & (1 << i))
-			tmp |= PRODIGY_WM_DATA;
-		else
-			tmp &= ~PRODIGY_WM_DATA;
-		snd_ice1712_gpio_write(ice, tmp);
-		udelay(1);
-		tmp |= PRODIGY_WM_CLK;
-		snd_ice1712_gpio_write(ice, tmp);
-		udelay(1);
-	}
-
-	tmp &= ~PRODIGY_WM_CLK;
-	tmp |= cs;
-	snd_ice1712_gpio_write(ice, tmp);
-	udelay(1);
-	tmp |= PRODIGY_WM_CLK;
-	snd_ice1712_gpio_write(ice, tmp);
-	udelay(1);
-}
-
-
-/*
- * get the current register value of WM codec
- */
-static unsigned short wm_get(ice1712_t *ice, int reg)
-{
-	reg <<= 1;
-	return ((unsigned short)ice->akm[0].images[reg] << 8) |
-		ice->akm[0].images[reg + 1];
-}
-
-/*
- * set the register value of WM codec and remember it
- */
-static void wm_put(ice1712_t *ice, int reg, unsigned short val)
-{
-	prodigy_spi_write(ice, PRODIGY_WM_CS, (reg << 9) | (val & 0x1ff), 16);
-	reg <<= 1;
-	ice->akm[0].images[reg] = val >> 8;
-	ice->akm[0].images[reg + 1] = val;
-}
-
-
-/*********************************
- ********* Controls section ******
- *********************************/
-
-#define PRODIGY_CON_HPAMP \
-        {                                            \
-                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,      \
-                .name =  "Headphone Amplifier", \
-                .info =  prodigy_hpamp_info,         \
-                .get =   prodigy_hpamp_get, \
-                .put =   prodigy_hpamp_put  \
-        }
-
-static int prodigy_hpamp_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
-{
-	static char *texts[2] = {
-		"Off", "On"
-	};
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-
-	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 prodigy_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-
-	ucontrol->value.integer.value[0] = prodigy_get_headphone_amp(ice);
-	return 0;
-}
-
-
-static int prodigy_hpamp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-
-	return prodigy_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
-}
-
-
-
-#define PRODIGY_CON_DEEMP \
-        {                                            \
-                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,      \
-                .name =  "DAC De-emphasis", \
-                .info =  prodigy_deemp_info,         \
-                .get =   prodigy_deemp_get, \
-                .put =   prodigy_deemp_put  \
-        }
-
-static int prodigy_deemp_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
-{
-	static char *texts[2] = { "Off", "On" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-
-	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 prodigy_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.integer.value[0] = (wm_get(ice, 0x15) & 0xf) == 0xf;
-	return 0;
-}
-
-static int prodigy_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int temp, temp2;
-	temp2 = temp = wm_get(ice, 0x15);
-	temp = (temp & ~0xf) | ((ucontrol->value.integer.value[0])*0xf);
-	if (temp != temp2) {
-		wm_put(ice,0x15,temp);
-		return 1;
-	}
-	return 0;
-}
-
-
-#define PRODIGY_CON_OVERSAMPLING \
-        {                                            \
-                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,      \
-                .name =  "ADC Oversampling", \
-                .info =  prodigy_oversampling_info,         \
-                .get =   prodigy_oversampling_get, \
-                .put =   prodigy_oversampling_put  \
-        }
-
-static int prodigy_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
-{
-	static char *texts[2] = { "128x", "64x"	};
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-
-	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 prodigy_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.integer.value[0] = (wm_get(ice, 0x17) & 0x8) == 0x8;
-	return 0;
-}
-
-static int prodigy_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	int temp, temp2;
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-
-	temp2 = temp = wm_get(ice, 0x17);
-
-	if( ucontrol->value.integer.value[0] ) {
-		temp |= 0x8;
-	} else {
-		temp &= ~0x8;
-	}
-
-	if (temp != temp2) {
-		wm_put(ice,0x17,temp);
-		return 1;
-	}
-	return 0;
-}
-
-
-
-
-/*
- * DAC volume attenuation mixer control
- */
-static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;		/* mute */
-	uinfo->value.integer.max = 101;		/* 0dB */
-	return 0;
-}
-
-static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
-	unsigned short vol;
-
-	down(&ice->gpio_mutex);
-	if (kcontrol->private_value)
-		idx = WM_DAC_MASTER_ATTEN;
-	else
-		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
-	vol = wm_get(ice, idx) & 0x7f;
-	if (vol <= 0x1a)
-		ucontrol->value.integer.value[0] = 0;
-	else
-		ucontrol->value.integer.value[0] = vol - 0x1a;
-	up(&ice->gpio_mutex);
-
-	return 0;
-}
-
-static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
-	unsigned short ovol, nvol;
-	int change;
-
-	snd_ice1712_save_gpio_status(ice);
-	if (kcontrol->private_value)
-		idx = WM_DAC_MASTER_ATTEN;
-	else
-		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
-	nvol = ucontrol->value.integer.value[0] + 0x1a;
-	ovol = wm_get(ice, idx) & 0x7f;
-	change = (ovol != nvol);
-	if (change) {
-		if (nvol <= 0x1a && ovol <= 0x1a)
-			change = 0;
-		else
-			wm_put(ice, idx, nvol | 0x180); /* update on zero detect */
-	}
-	snd_ice1712_restore_gpio_status(ice);
-	return change;
-}
-
-/*
- * ADC gain mixer control
- */
-static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;		/* -12dB */
-	uinfo->value.integer.max = 0x1f;	/* 19dB */
-	return 0;
-}
-
-static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
-	unsigned short vol;
-
-	down(&ice->gpio_mutex);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
-	vol = wm_get(ice, idx) & 0x1f;
-	ucontrol->value.integer.value[0] = vol;
-	up(&ice->gpio_mutex);
-	return 0;
-}
-
-static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
-	unsigned short ovol, nvol;
-	int change;
-
-	snd_ice1712_save_gpio_status(ice);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
-	nvol = ucontrol->value.integer.value[0];
-	ovol = wm_get(ice, idx) & 0x1f;
-	change = (ovol != nvol);
-	if (change)
-		wm_put(ice, idx, nvol);
-	snd_ice1712_restore_gpio_status(ice);
-	return change;
-}
-
-/*
- * ADC input mux mixer control
- */
-static int wm_adc_mux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
-{
-	static char *texts[] = {
-		"CD Left",
-		"CD Right",
-		"Line Left",
-		"Line Right",
-		"Aux Left",
-		"Aux Right",
-		"Mic Left",
-		"Mic Right",
-	};
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 2;
-	uinfo->value.enumerated.items = 8;
-	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 wm_adc_mux_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	down(&ice->gpio_mutex);
-	val = wm_get(ice, WM_ADC_MUX);
-	ucontrol->value.integer.value[0] = val & 7;
-	ucontrol->value.integer.value[1] = (val >> 4) & 7;
-	up(&ice->gpio_mutex);
-	return 0;
-}
-
-static int wm_adc_mux_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	unsigned short oval, nval;
-	int change;
-
-	snd_ice1712_save_gpio_status(ice);
-	oval = wm_get(ice, WM_ADC_MUX);
-	nval = oval & ~0x77;
-	nval |= ucontrol->value.integer.value[0] & 7;
-	nval |= (ucontrol->value.integer.value[1] & 7) << 4;
-	change = (oval != nval);
-	if (change)
-		wm_put(ice, WM_ADC_MUX, nval);
-	snd_ice1712_restore_gpio_status(ice);
-	return 0;
-}
-
-/*
- * mixers
- */
-
-static snd_kcontrol_new_t prodigy71_dac_control __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "DAC Volume",
-	.count = 8,
-	.info = wm_dac_vol_info,
-	.get = wm_dac_vol_get,
-	.put = wm_dac_vol_put,
-};
-
-static snd_kcontrol_new_t wm_controls[] __devinitdata = {
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Volume",
-		.info = wm_dac_vol_info,
-		.get = wm_dac_vol_get,
-		.put = wm_dac_vol_put,
-		.private_value = 1,
-	},
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "ADC Volume",
-		.count = 2,
-		.info = wm_adc_vol_info,
-		.get = wm_adc_vol_get,
-		.put = wm_adc_vol_put,
-	},
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Route",
-		.info = wm_adc_mux_info,
-		.get = wm_adc_mux_get,
-		.put = wm_adc_mux_put,
-	},
-	PRODIGY_CON_HPAMP ,
-	PRODIGY_CON_DEEMP ,
-	PRODIGY_CON_OVERSAMPLING
-};
-
-
-static int __devinit prodigy_add_controls(ice1712_t *ice)
-{
-	unsigned int i;
-	int err;
-
-	err = snd_ctl_add(ice->card, snd_ctl_new1(&prodigy71_dac_control, ice));
-	if (err < 0)
-		return err;
-
-	for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
-		if (err < 0)
-			return err;
-	}
-	return 0;
-}
-
-
-/*
- * initialize the chip
- */
-static int __devinit prodigy_init(ice1712_t *ice)
-{
-	static unsigned short wm_inits[] = {
-
-		/* These come first to reduce init pop noise */
-		0x1b, 0x000,		/* ADC Mux */
-		0x1c, 0x009,		/* Out Mux1 */
-		0x1d, 0x009,		/* Out Mux2 */
-
-		0x18, 0x000,		/* All power-up */
-
-		0x16, 0x022,		/* I2S, normal polarity, 24bit, high-pass on */
-		0x17, 0x006,		/* 128fs, slave mode */
-
-		0x00, 0,		/* DAC1 analog mute */
-		0x01, 0,		/* DAC2 analog mute */
-		0x02, 0,		/* DAC3 analog mute */
-		0x03, 0,		/* DAC4 analog mute */
-		0x04, 0,		/* DAC5 analog mute */
-		0x05, 0,		/* DAC6 analog mute */
-		0x06, 0,		/* DAC7 analog mute */
-		0x07, 0,		/* DAC8 analog mute */
-		0x08, 0x100,		/* master analog mute */
-
-		0x09, 0x7f,		/* DAC1 digital full */
-		0x0a, 0x7f,		/* DAC2 digital full */
-		0x0b, 0x7f,		/* DAC3 digital full */
-		0x0c, 0x7f,		/* DAC4 digital full */
-		0x0d, 0x7f,		/* DAC5 digital full */
-		0x0e, 0x7f,		/* DAC6 digital full */
-		0x0f, 0x7f,		/* DAC7 digital full */
-		0x10, 0x7f,		/* DAC8 digital full */
-		0x11, 0x1FF,		/* master digital full */
-
-		0x12, 0x000,		/* phase normal */
-		0x13, 0x090,		/* unmute DAC L/R */
-		0x14, 0x000,		/* all unmute */
-		0x15, 0x000,		/* no deemphasis, no ZFLG */
-
-		0x19, 0x000,		/* -12dB ADC/L */
-		0x1a, 0x000		/* -12dB ADC/R */
-
-	};
-
-	static unsigned short cs_inits[] = {
-		0x0441, /* RUN */
-		0x0100, /* no mute */
-		0x0200, /* */
-		0x0600, /* slave, 24bit */
-	};
-
-	unsigned int tmp;
-	unsigned int i;
-
-	printk(KERN_INFO "ice1724: AudioTrak Prodigy 7.1 driver rev. 0.82b\n");
-	printk(KERN_INFO "ice1724:   This driver is in beta stage. Forsuccess/failure reporting contact\n");
-	printk(KERN_INFO "ice1724:   Apostolos Dimitromanolakis <apostol@cs.utoronto.ca>\n");
-
-	ice->num_total_dacs = 8;
-	ice->num_total_adcs = 8;
-
-	/* to remeber the register values */
-	ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL);
-	if (! ice->akm)
-		return -ENOMEM;
-	ice->akm_codecs = 1;
-
-	snd_ice1712_gpio_set_dir(ice, 0xbfffff); /* fix this for the time being */
-
-	/* reset the wm codec as the SPI mode */
-	snd_ice1712_save_gpio_status(ice);
-	snd_ice1712_gpio_set_mask(ice,~( PRODIGY_WM_RESET|PRODIGY_WM_CS|
-		PRODIGY_CS8415_CS|PRODIGY_HP_AMP_EN ));
-
-	tmp = snd_ice1712_gpio_read(ice);
-	tmp &= ~PRODIGY_WM_RESET;
-	snd_ice1712_gpio_write(ice, tmp);
-	udelay(1);
-	tmp |= PRODIGY_WM_CS | PRODIGY_CS8415_CS;
-	snd_ice1712_gpio_write(ice, tmp);
-	udelay(1);
-	tmp |= PRODIGY_WM_RESET;
-	snd_ice1712_gpio_write(ice, tmp);
-	udelay(1);
-
-	/* initialize WM8770 codec */
-	for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
-		wm_put(ice, wm_inits[i], wm_inits[i+1]);
-
-	/* initialize CS8415A codec */
-	for (i = 0; i < ARRAY_SIZE(cs_inits); i++)
-		prodigy_spi_write(ice, PRODIGY_CS8415_CS,
-				 cs_inits[i] | 0x200000, 24);
-
-
-	prodigy_set_headphone_amp(ice, 1);
-
-	snd_ice1712_restore_gpio_status(ice);
-
-	return 0;
-}
-
-/*
- * Prodigy boards don't provide the EEPROM data except for the vendor IDs.
- * hence the driver needs to sets up it properly.
- */
-
-static unsigned char prodigy71_eeprom[] __devinitdata = {
-	0x2b,	/* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */
-	0x80,	/* ACLINK: I2S */
-	0xf8,	/* I2S: vol, 96k, 24bit, 192k */
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0xff,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0xbf,	/* GPIO_DIR2 */
-	0x00,	/* GPIO_MASK */
-	0x00,	/* GPIO_MASK1 */
-	0x00,	/* GPIO_MASK2 */
-	0x00,	/* GPIO_STATE */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 */
-};
-
-/* entry point */
-struct snd_ice1712_card_info snd_vt1724_prodigy_cards[] __devinitdata = {
-	{
-		.subvendor = VT1724_SUBDEVICE_PRODIGY71,
-		.name = "Audiotrak Prodigy 7.1",
-		.chip_init = prodigy_init,
-		.build_controls = prodigy_add_controls,
-		.eeprom_size = sizeof(prodigy71_eeprom),
-		.eeprom_data = prodigy71_eeprom,
-	},
-	{ } /* terminator */
-};
--- diff/sound/pci/ice1712/prodigy.h	2004-05-19 22:13:25.000000000 +0100
+++ source/sound/pci/ice1712/prodigy.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,67 +0,0 @@
-#ifndef __SOUND_PRODIGY_H
-#define __SOUND_PRODIGY_H
-
-/*
- *   ALSA driver for VIA VT1724 (Envy24HT)
- *
- *   Lowlevel functions for Terratec PRODIGY cards
- *
- *	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  PRODIGY_DEVICE_DESC 	       "{AudioTrak,Prodigy 7.1},"
-
-#define VT1724_SUBDEVICE_PRODIGY71	0x33495345	/* PRODIGY 7.1 */
-
-extern struct snd_ice1712_card_info  snd_vt1724_prodigy_cards[];
-
-/* GPIO bits */
-#define PRODIGY_CS8415_CS	(1 << 23)
-#define PRODIGY_CS8415_CDTO	(1 << 22)
-#define PRODIGY_WM_RESET	(1 << 20)
-#define PRODIGY_WM_CLK		(1 << 19)
-#define PRODIGY_WM_DATA		(1 << 18)
-#define PRODIGY_WM_RW		(1 << 17)
-#define PRODIGY_AC97_RESET	(1 << 16)
-#define PRODIGY_DIGITAL_SEL1	(1 << 15)
-// #define PRODIGY_HP_SEL		(1 << 14)
-#define PRODIGY_WM_CS		(1 << 12)
-
-#define PRODIGY_HP_AMP_EN	(1 << 14)
-
-
-/* WM8770 registers */
-#define WM_DAC_ATTEN		0x00	/* DAC1-8 analog attenuation */
-#define WM_DAC_MASTER_ATTEN	0x08	/* DAC master analog attenuation */
-#define WM_DAC_DIG_ATTEN	0x09	/* DAC1-8 digital attenuation */
-#define WM_DAC_DIG_MATER_ATTEN	0x11	/* DAC master digital attenuation */
-#define WM_PHASE_SWAP		0x12	/* DAC phase */
-#define WM_DAC_CTRL1		0x13	/* DAC control bits */
-#define WM_MUTE			0x14	/* mute controls */
-#define WM_DAC_CTRL2		0x15	/* de-emphasis and zefo-flag */
-#define WM_INT_CTRL		0x16	/* interface control */
-#define WM_MASTER		0x17	/* master clock and mode */
-#define WM_POWERDOWN		0x18	/* power-down controls */
-#define WM_ADC_GAIN		0x19	/* ADC gain L(19)/R(1a) */
-#define WM_ADC_MUX		0x1b	/* input MUX */
-#define WM_OUT_MUX1		0x1c	/* output MUX */
-#define WM_OUT_MUX2		0x1e	/* output MUX */
-#define WM_RESET		0x1f	/* software reset */
-
-
-#endif /* __SOUND_PRODIGY_H */
